setup.py 8.71 KB
Newer Older
Adrien Di Mascio's avatar
Adrien Di Mascio committed
1
#!/usr/bin/env python
Sylvain Thénault's avatar
Sylvain Thénault committed
2
# pylint: disable=W0142,W0403,W0404,W0613,W0622,W0622,W0704,R0904,C0103,E0611
Adrien Di Mascio's avatar
Adrien Di Mascio committed
3
#
4
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
5
6
7
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
Adrien Di Mascio's avatar
Adrien Di Mascio committed
8
#
9
10
11
12
13
# CubicWeb is free software: you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
#
14
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
Adrien Di Mascio's avatar
Adrien Di Mascio committed
15
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16
17
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
Adrien Di Mascio's avatar
Adrien Di Mascio committed
18
#
19
20
21
22
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
"""Generic Setup script, takes package info from __pkginfo__.py file
"""
Adrien Di Mascio's avatar
Adrien Di Mascio committed
23
24
25
26
27
28
29

import os
import sys
import shutil
from os.path import isdir, exists, join, walk

try:
Sylvain Thénault's avatar
cleanup    
Sylvain Thénault committed
30
31
32
33
34
    if os.environ.get('NO_SETUPTOOLS'):
        raise ImportError() # do as there is no setuptools
    from setuptools import setup
    from setuptools.command import install_lib
    USE_SETUPTOOLS = True
Adrien Di Mascio's avatar
Adrien Di Mascio committed
35
except ImportError:
Sylvain Thénault's avatar
cleanup    
Sylvain Thénault committed
36
37
38
    from distutils.core import setup
    from distutils.command import install_lib
    USE_SETUPTOOLS = False
39
from distutils.command import install_data
40
41
42
43
44

# import required features
from __pkginfo__ import modname, version, license, description, web, \
     author, author_email

45
long_description = file('README').read()
46
47
48
49

# import optional features
import __pkginfo__
if USE_SETUPTOOLS:
Sylvain Thénault's avatar
cleanup    
Sylvain Thénault committed
50
    requires = {}
51
    for entry in ("__depends__",): # "__recommends__"):
Sylvain Thénault's avatar
cleanup    
Sylvain Thénault committed
52
53
        requires.update(getattr(__pkginfo__, entry, {}))
    install_requires = [("%s %s" % (d, v and v or "")).strip()
54
55
                       for d, v in requires.iteritems()]
else:
Sylvain Thénault's avatar
cleanup    
Sylvain Thénault committed
56
    install_requires = []
57
58
59
60
61
62
63

distname = getattr(__pkginfo__, 'distname', modname)
scripts = getattr(__pkginfo__, 'scripts', ())
include_dirs = getattr(__pkginfo__, 'include_dirs', ())
data_files = getattr(__pkginfo__, 'data_files', None)
subpackage_of = getattr(__pkginfo__, 'subpackage_of', None)
ext_modules = getattr(__pkginfo__, 'ext_modules', None)
64
package_data = getattr(__pkginfo__, 'package_data', {})
Adrien Di Mascio's avatar
Adrien Di Mascio committed
65

66
BASE_BLACKLIST = ('CVS', 'dist', 'build', '__buildlog')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
67
IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc')
68

Adrien Di Mascio's avatar
Adrien Di Mascio committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

def ensure_scripts(linux_scripts):
    """
    Creates the proper script names required for each platform
    (taken from 4Suite)
    """
    from distutils import util
    if util.get_platform()[:3] == 'win':
        scripts_ = [script + '.bat' for script in linux_scripts]
    else:
        scripts_ = linux_scripts
    return scripts_


def get_packages(directory, prefix):
    """return a list of subpackages for the given directory
    """
    result = []
    for package in os.listdir(directory):
        absfile = join(directory, package)
        if isdir(absfile):
            if exists(join(absfile, '__init__.py')) or \
                   package in ('test', 'tests'):
                if prefix:
                    result.append('%s.%s' % (prefix, package))
                else:
                    result.append(package)
                result += get_packages(absfile, result[-1])
    return result

def export(from_dir, to_dir,
           blacklist=BASE_BLACKLIST,
101
102
           ignore_ext=IGNORED_EXTENSIONS,
           verbose=True):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    """make a mirror of from_dir in to_dir, omitting directories and files
    listed in the black list
    """
    def make_mirror(arg, directory, fnames):
        """walk handler"""
        for norecurs in blacklist:
            try:
                fnames.remove(norecurs)
            except ValueError:
                pass
        for filename in fnames:
            # don't include binary files
            if filename[-4:] in ignore_ext:
                continue
            if filename[-1] == '~':
                continue
            src = '%s/%s' % (directory, filename)
            dest = to_dir + src[len(from_dir):]
121
            if verbose:
122
               sys.stderr.write('%s -> %s\n' % (src, dest))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
123
124
125
126
127
128
129
130
131
            if os.path.isdir(src):
                if not exists(dest):
                    os.mkdir(dest)
            else:
                if exists(dest):
                    os.remove(dest)
                shutil.copy2(src, dest)
    try:
        os.mkdir(to_dir)
132
    except OSError as ex:
Adrien Di Mascio's avatar
Adrien Di Mascio committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
        # file exists ?
        import errno
        if ex.errno != errno.EEXIST:
            raise
    walk(from_dir, make_mirror, None)


EMPTY_FILE = '"""generated file, don\'t modify or your data will be lost"""\n'

class MyInstallLib(install_lib.install_lib):
    """extend install_lib command to handle  package __init__.py and
    include_dirs variable if necessary
    """
    def run(self):
        """overridden from install_lib class"""
        install_lib.install_lib.run(self)
        # create Products.__init__.py if needed
        if subpackage_of:
            product_init = join(self.install_dir, subpackage_of, '__init__.py')
            if not exists(product_init):
                self.announce('creating %s' % product_init)
                stream = open(product_init, 'w')
                stream.write(EMPTY_FILE)
                stream.close()
        # manually install included directories if any
        if include_dirs:
            if subpackage_of:
                base = join(subpackage_of, modname)
            else:
                base = modname
            for directory in include_dirs:
                dest = join(self.install_dir, base, directory)
165
                export(directory, dest, verbose=False)
166

167
# write required share/cubicweb/cubes/__init__.py
168
class MyInstallData(install_data.install_data):
169
    """A class That manages data files installation"""
170
171
172
173
174
175
176
177
    def run(self):
        """overridden from install_data class"""
        install_data.install_data.run(self)
        path = join(self.install_dir, 'share', 'cubicweb', 'cubes', '__init__.py')
        ini = open(path, 'w')
        ini.write('# Cubicweb cubes directory\n')
        ini.close()

178
179
180
181
# re-enable copying data files in sys.prefix
if USE_SETUPTOOLS:
    # overwrite MyInstallData to use sys.prefix instead of the egg directory
    MyInstallMoreData = MyInstallData
182
    class MyInstallData(MyInstallMoreData): # pylint: disable=E0102
183
184
185
186
187
188
189
190
        """A class that manages data files installation"""
        def run(self):
            _old_install_dir = self.install_dir
            if self.install_dir.endswith('egg'):
                self.install_dir = sys.prefix
            MyInstallMoreData.run(self)
            self.install_dir = _old_install_dir
    try:
191
        import setuptools.command.easy_install # only if easy_install available
192
193
194
195
196
        # monkey patch: Crack SandboxViolation verification
        from setuptools.sandbox import DirectorySandbox as DS
        old_ok = DS._ok
        def _ok(self, path):
            """Return True if ``path`` can be written during installation."""
197
            out = old_ok(self, path) # here for side effect from setuptools
198
            realpath = os.path.normcase(os.path.realpath(path))
199
200
            allowed_path = os.path.normcase(sys.prefix)
            if realpath.startswith(allowed_path):
201
202
203
204
205
                out = True
            return out
        DS._ok = _ok
    except ImportError:
        pass
206

Adrien Di Mascio's avatar
Adrien Di Mascio committed
207
208
def install(**kwargs):
    """setup entry point"""
209
210
211
212
213
214
    if USE_SETUPTOOLS:
        if '--force-manifest' in sys.argv:
            sys.argv.remove('--force-manifest')
    # install-layout option was introduced in 2.5.3-1~exp1
    elif sys.version_info < (2, 5, 4) and '--install-layout=deb' in sys.argv:
        sys.argv.remove('--install-layout=deb')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
215
216
217
218
    if subpackage_of:
        package = subpackage_of + '.' + modname
        kwargs['package_dir'] = {package : '.'}
        packages = [package] + get_packages(os.getcwd(), package)
219
220
        if USE_SETUPTOOLS:
            kwargs['namespace_packages'] = [subpackage_of]
Adrien Di Mascio's avatar
Adrien Di Mascio committed
221
222
223
    else:
        kwargs['package_dir'] = {modname : '.'}
        packages = [modname] + get_packages(os.getcwd(), modname)
224
    if USE_SETUPTOOLS:
Sylvain Thénault's avatar
cleanup    
Sylvain Thénault committed
225
        kwargs['install_requires'] = install_requires
Alain Leufroy's avatar
Alain Leufroy committed
226
        kwargs['zip_safe'] = False
Adrien Di Mascio's avatar
Adrien Di Mascio committed
227
    kwargs['packages'] = packages
228
    kwargs['package_data'] = package_data
229
230
231
232
    return setup(name=distname, version=version, license=license, url=web,
                 description=description, long_description=long_description,
                 author=author, author_email=author_email,
                 scripts=ensure_scripts(scripts), data_files=data_files,
Adrien Di Mascio's avatar
Adrien Di Mascio committed
233
                 ext_modules=ext_modules,
234
235
                 cmdclass={'install_lib': MyInstallLib,
                           'install_data': MyInstallData},
Adrien Di Mascio's avatar
Adrien Di Mascio committed
236
237
                 **kwargs
                 )
238

Adrien Di Mascio's avatar
Adrien Di Mascio committed
239
240
if __name__ == '__main__' :
    install()