~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: Martin Pool
  • Date: 2005-08-29 05:13:54 UTC
  • Revision ID: mbp@sourcefrog.net-20050829051353-656edb4fe57910a6
- better debug log for loading of plugins

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#! /usr/bin/env python
2
2
 
3
 
"""Installation script for bzr.
4
 
Run it with
5
 
 './setup.py install', or
6
 
 './setup.py --help' for more options
7
 
"""
8
 
 
9
 
import os
10
 
import os.path
11
 
import sys
12
 
 
13
 
if sys.version_info < (2, 4):
14
 
    sys.stderr.write("[ERROR] Not a supported Python version. Need 2.4+\n")
15
 
    sys.exit(1)
16
 
 
17
 
# NOTE: The directory containing setup.py, whether run by 'python setup.py' or
18
 
# './setup.py' or the equivalent with another path, should always be at the
19
 
# start of the path, so this should find the right one...
20
 
import bzrlib
21
 
 
22
 
def get_long_description():
23
 
    dirname = os.path.dirname(__file__)
24
 
    readme = os.path.join(dirname, 'README')
25
 
    f = open(readme, 'rb')
26
 
    try:
27
 
        return f.read()
28
 
    finally:
29
 
        f.close()
30
 
 
31
 
 
32
 
##
33
 
# META INFORMATION FOR SETUP
34
 
# see http://docs.python.org/dist/meta-data.html
35
 
META_INFO = {
36
 
    'name':         'bzr',
37
 
    'version':      bzrlib.__version__,
38
 
    'author':       'Canonical Ltd',
39
 
    'author_email': 'bazaar@lists.canonical.com',
40
 
    'url':          'http://bazaar.canonical.com/',
41
 
    'description':  'Friendly distributed version control system',
42
 
    'license':      'GNU GPL v2',
43
 
    'download_url': 'https://launchpad.net/bzr/+download',
44
 
    'long_description': get_long_description(),
45
 
    'classifiers': [
46
 
        'Development Status :: 6 - Mature',
47
 
        'Environment :: Console',
48
 
        'Intended Audience :: Developers',
49
 
        'Intended Audience :: System Administrators',
50
 
        'License :: OSI Approved :: GNU General Public License (GPL)',
51
 
        'Operating System :: Microsoft :: Windows',
52
 
        'Operating System :: OS Independent',
53
 
        'Operating System :: POSIX',
54
 
        'Programming Language :: Python',
55
 
        'Programming Language :: C',
56
 
        'Topic :: Software Development :: Version Control',
57
 
        ],
58
 
    }
59
 
 
60
 
# The list of packages is automatically generated later. Add other things
61
 
# that are part of BZRLIB here.
62
 
BZRLIB = {}
63
 
 
64
 
PKG_DATA = {# install files from selftest suite
65
 
            'package_data': {'bzrlib': ['doc/api/*.txt',
66
 
                                        'tests/test_patches_data/*',
67
 
                                        'help_topics/en/*.txt',
68
 
                                        'tests/ssl_certs/server_without_pass.key',
69
 
                                        'tests/ssl_certs/server_with_pass.key',
70
 
                                        'tests/ssl_certs/server.crt'
71
 
                                       ]},
72
 
           }
73
 
 
74
 
 
75
 
def get_bzrlib_packages():
76
 
    """Recurse through the bzrlib directory, and extract the package names"""
77
 
 
78
 
    packages = []
79
 
    base_path = os.path.dirname(os.path.abspath(bzrlib.__file__))
80
 
    for root, dirs, files in os.walk(base_path):
81
 
        if '__init__.py' in files:
82
 
            assert root.startswith(base_path)
83
 
            # Get just the path below bzrlib
84
 
            package_path = root[len(base_path):]
85
 
            # Remove leading and trailing slashes
86
 
            package_path = package_path.strip('\\/')
87
 
            if not package_path:
88
 
                package_name = 'bzrlib'
89
 
            else:
90
 
                package_name = ('bzrlib.' +
91
 
                            package_path.replace('/', '.').replace('\\', '.'))
92
 
            packages.append(package_name)
93
 
    return sorted(packages)
94
 
 
95
 
 
96
 
BZRLIB['packages'] = get_bzrlib_packages()
97
 
 
98
 
 
99
 
from distutils import log
 
3
# This is an installation script for bzr.  Run it with
 
4
# './setup.py install', or
 
5
# './setup.py --help' for more options
 
6
 
100
7
from distutils.core import setup
101
 
from distutils.command.install_scripts import install_scripts
102
 
from distutils.command.install_data import install_data
103
 
from distutils.command.build import build
104
 
 
105
 
###############################
106
 
# Overridden distutils actions
107
 
###############################
108
 
 
109
 
class my_install_scripts(install_scripts):
110
 
    """ Customized install_scripts distutils action.
111
 
    Create bzr.bat for win32.
112
 
    """
113
 
    def run(self):
114
 
        install_scripts.run(self)   # standard action
115
 
 
116
 
        if sys.platform == "win32":
117
 
            try:
118
 
                scripts_dir = os.path.join(sys.prefix, 'Scripts')
119
 
                script_path = self._quoted_path(os.path.join(scripts_dir,
120
 
                                                             "bzr"))
121
 
                python_exe = self._quoted_path(sys.executable)
122
 
                args = self._win_batch_args()
123
 
                batch_str = "@%s %s %s" % (python_exe, script_path, args)
124
 
                batch_path = os.path.join(self.install_dir, "bzr.bat")
125
 
                f = file(batch_path, "w")
126
 
                f.write(batch_str)
127
 
                f.close()
128
 
                print("Created: %s" % batch_path)
129
 
            except Exception:
130
 
                e = sys.exc_info()[1]
131
 
                print("ERROR: Unable to create %s: %s" % (batch_path, e))
132
 
 
133
 
    def _quoted_path(self, path):
134
 
        if ' ' in path:
135
 
            return '"' + path + '"'
136
 
        else:
137
 
            return path
138
 
 
139
 
    def _win_batch_args(self):
140
 
        from bzrlib.win32utils import winver
141
 
        if winver == 'Windows NT':
142
 
            return '%*'
143
 
        else:
144
 
            return '%1 %2 %3 %4 %5 %6 %7 %8 %9'
145
 
#/class my_install_scripts
146
 
 
147
 
 
148
 
class bzr_build(build):
149
 
    """Customized build distutils action.
150
 
    Generate bzr.1.
151
 
    """
152
 
 
153
 
    def run(self):
154
 
        build.run(self)
155
 
 
156
 
        from tools import generate_docs
157
 
        generate_docs.main(argv=["bzr", "man"])
158
 
 
159
 
 
160
 
########################
161
 
## Setup
162
 
########################
163
 
 
164
 
command_classes = {'install_scripts': my_install_scripts,
165
 
                   'build': bzr_build}
166
 
from distutils import log
167
 
from distutils.errors import CCompilerError, DistutilsPlatformError
168
 
from distutils.extension import Extension
169
 
ext_modules = []
170
 
try:
171
 
    try:
172
 
        from Pyrex.Distutils import build_ext
173
 
        from Pyrex.Compiler.Version import version as pyrex_version
174
 
    except ImportError:
175
 
        print("No Pyrex, trying Cython...")
176
 
        from Cython.Distutils import build_ext
177
 
        from Cython.Compiler.Version import version as pyrex_version
178
 
except ImportError:
179
 
    have_pyrex = False
180
 
    # try to build the extension from the prior generated source.
181
 
    print("")
182
 
    print("The python package 'Pyrex' is not available."
183
 
          " If the .c files are available,")
184
 
    print("they will be built,"
185
 
          " but modifying the .pyx files will not rebuild them.")
186
 
    print("")
187
 
    from distutils.command.build_ext import build_ext
188
 
else:
189
 
    have_pyrex = True
190
 
    pyrex_version_info = tuple(map(int, pyrex_version.split('.')))
191
 
 
192
 
 
193
 
class build_ext_if_possible(build_ext):
194
 
 
195
 
    user_options = build_ext.user_options + [
196
 
        ('allow-python-fallback', None,
197
 
         "When an extension cannot be built, allow falling"
198
 
         " back to the pure-python implementation.")
199
 
        ]
200
 
 
201
 
    def initialize_options(self):
202
 
        build_ext.initialize_options(self)
203
 
        self.allow_python_fallback = False
204
 
 
205
 
    def run(self):
206
 
        try:
207
 
            build_ext.run(self)
208
 
        except DistutilsPlatformError:
209
 
            e = sys.exc_info()[1]
210
 
            if not self.allow_python_fallback:
211
 
                log.warn('\n  Cannot build extensions.\n'
212
 
                         '  Use "build_ext --allow-python-fallback" to use'
213
 
                         ' slower python implementations instead.\n')
214
 
                raise
215
 
            log.warn(str(e))
216
 
            log.warn('\n  Extensions cannot be built.\n'
217
 
                     '  Using the slower Python implementations instead.\n')
218
 
 
219
 
    def build_extension(self, ext):
220
 
        try:
221
 
            build_ext.build_extension(self, ext)
222
 
        except CCompilerError:
223
 
            if not self.allow_python_fallback:
224
 
                log.warn('\n  Cannot build extension "%s".\n'
225
 
                         '  Use "build_ext --allow-python-fallback" to use'
226
 
                         ' slower python implementations instead.\n'
227
 
                         % (ext.name,))
228
 
                raise
229
 
            log.warn('\n  Building of "%s" extension failed.\n'
230
 
                     '  Using the slower Python implementation instead.'
231
 
                     % (ext.name,))
232
 
 
233
 
 
234
 
# Override the build_ext if we have Pyrex available
235
 
command_classes['build_ext'] = build_ext_if_possible
236
 
unavailable_files = []
237
 
 
238
 
 
239
 
def add_pyrex_extension(module_name, libraries=None, extra_source=[]):
240
 
    """Add a pyrex module to build.
241
 
 
242
 
    This will use Pyrex to auto-generate the .c file if it is available.
243
 
    Otherwise it will fall back on the .c file. If the .c file is not
244
 
    available, it will warn, and not add anything.
245
 
 
246
 
    You can pass any extra options to Extension through kwargs. One example is
247
 
    'libraries = []'.
248
 
 
249
 
    :param module_name: The python path to the module. This will be used to
250
 
        determine the .pyx and .c files to use.
251
 
    """
252
 
    path = module_name.replace('.', '/')
253
 
    pyrex_name = path + '.pyx'
254
 
    c_name = path + '.c'
255
 
    define_macros = []
256
 
    if sys.platform == 'win32':
257
 
        # pyrex uses the macro WIN32 to detect the platform, even though it
258
 
        # should be using something like _WIN32 or MS_WINDOWS, oh well, we can
259
 
        # give it the right value.
260
 
        define_macros.append(('WIN32', None))
261
 
    if have_pyrex:
262
 
        source = [pyrex_name]
263
 
    else:
264
 
        if not os.path.isfile(c_name):
265
 
            unavailable_files.append(c_name)
266
 
            return
267
 
        else:
268
 
            source = [c_name]
269
 
    source.extend(extra_source)
270
 
    ext_modules.append(Extension(module_name, source,
271
 
        define_macros=define_macros, libraries=libraries))
272
 
 
273
 
 
274
 
add_pyrex_extension('bzrlib._annotator_pyx')
275
 
add_pyrex_extension('bzrlib._bencode_pyx')
276
 
add_pyrex_extension('bzrlib._chunks_to_lines_pyx')
277
 
add_pyrex_extension('bzrlib._groupcompress_pyx',
278
 
                    extra_source=['bzrlib/diff-delta.c'])
279
 
add_pyrex_extension('bzrlib._knit_load_data_pyx')
280
 
add_pyrex_extension('bzrlib._known_graph_pyx')
281
 
add_pyrex_extension('bzrlib._rio_pyx')
282
 
if sys.platform == 'win32':
283
 
    add_pyrex_extension('bzrlib._dirstate_helpers_pyx',
284
 
                        libraries=['Ws2_32'])
285
 
    add_pyrex_extension('bzrlib._walkdirs_win32')
286
 
else:
287
 
    if have_pyrex and pyrex_version_info[:3] == (0,9,4):
288
 
        # Pyrex 0.9.4.1 fails to compile this extension correctly
289
 
        # The code it generates re-uses a "local" pointer and
290
 
        # calls "PY_DECREF" after having set it to NULL. (It mixes PY_XDECREF
291
 
        # which is NULL safe with PY_DECREF which is not.)
292
 
        # <https://bugs.edge.launchpad.net/bzr/+bug/449372>
293
 
        # <https://bugs.edge.launchpad.net/bzr/+bug/276868>
294
 
        print('Cannot build extension "bzrlib._dirstate_helpers_pyx" using')
295
 
        print('your version of pyrex "%s". Please upgrade your pyrex' % (
296
 
            pyrex_version,))
297
 
        print('install. For now, the non-compiled (python) version will')
298
 
        print('be used instead.')
299
 
    else:
300
 
        add_pyrex_extension('bzrlib._dirstate_helpers_pyx')
301
 
    add_pyrex_extension('bzrlib._readdir_pyx')
302
 
add_pyrex_extension('bzrlib._chk_map_pyx')
303
 
ext_modules.append(Extension('bzrlib._patiencediff_c',
304
 
                             ['bzrlib/_patiencediff_c.c']))
305
 
if have_pyrex and pyrex_version_info < (0, 9, 6, 3):
306
 
    print("")
307
 
    print('Your Pyrex/Cython version %s is too old to build the simple_set' % (
308
 
        pyrex_version))
309
 
    print('and static_tuple extensions.')
310
 
    print('Please upgrade to at least Pyrex 0.9.6.3')
311
 
    print("")
312
 
    # TODO: Should this be a fatal error?
313
 
else:
314
 
    # We only need 0.9.6.3 to build _simple_set_pyx, but static_tuple depends
315
 
    # on simple_set
316
 
    add_pyrex_extension('bzrlib._simple_set_pyx')
317
 
    ext_modules.append(Extension('bzrlib._static_tuple_c',
318
 
                                 ['bzrlib/_static_tuple_c.c']))
319
 
add_pyrex_extension('bzrlib._btree_serializer_pyx')
320
 
 
321
 
 
322
 
if unavailable_files:
323
 
    print('C extension(s) not found:')
324
 
    print('   %s' % ('\n  '.join(unavailable_files),))
325
 
    print('The python versions will be used instead.')
326
 
    print("")
327
 
 
328
 
 
329
 
def get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
330
 
                         gui_targets, data_files):
331
 
    packages.append('tbzrcommands')
332
 
 
333
 
    # ModuleFinder can't handle runtime changes to __path__, but
334
 
    # win32com uses them.  Hook this in so win32com.shell is found.
335
 
    import modulefinder
336
 
    import win32com
337
 
    import cPickle as pickle
338
 
    for p in win32com.__path__[1:]:
339
 
        modulefinder.AddPackagePath("win32com", p)
340
 
    for extra in ["win32com.shell"]:
341
 
        __import__(extra)
342
 
        m = sys.modules[extra]
343
 
        for p in m.__path__[1:]:
344
 
            modulefinder.AddPackagePath(extra, p)
345
 
 
346
 
    # TBZR points to the TBZR directory
347
 
    tbzr_root = os.environ["TBZR"]
348
 
 
349
 
    # Ensure tbzrlib itself is on sys.path
350
 
    sys.path.append(tbzr_root)
351
 
 
352
 
    packages.append("tbzrlib")
353
 
 
354
 
    # collect up our icons.
355
 
    cwd = os.getcwd()
356
 
    ico_root = os.path.join(tbzr_root, 'tbzrlib', 'resources')
357
 
    icos = [] # list of (path_root, relative_ico_path)
358
 
    # First always bzr's icon and its in the root of the bzr tree.
359
 
    icos.append(('', 'bzr.ico'))
360
 
    for root, dirs, files in os.walk(ico_root):
361
 
        icos.extend([(ico_root, os.path.join(root, f)[len(ico_root)+1:])
362
 
                     for f in files if f.endswith('.ico')])
363
 
    # allocate an icon ID for each file and the full path to the ico
364
 
    icon_resources = [(rid, os.path.join(ico_dir, ico_name))
365
 
                      for rid, (ico_dir, ico_name) in enumerate(icos)]
366
 
    # create a string resource with the mapping.  Might as well save the
367
 
    # runtime some effort and write a pickle.
368
 
    # Runtime expects unicode objects with forward-slash seps.
369
 
    fse = sys.getfilesystemencoding()
370
 
    map_items = [(f.replace('\\', '/').decode(fse), rid)
371
 
                 for rid, (_, f) in enumerate(icos)]
372
 
    ico_map = dict(map_items)
373
 
    # Create a new resource type of 'ICON_MAP', and use ID=1
374
 
    other_resources = [ ("ICON_MAP", 1, pickle.dumps(ico_map))]
375
 
 
376
 
    excludes.extend("""pywin pywin.dialogs pywin.dialogs.list
377
 
                       win32ui crawler.Crawler""".split())
378
 
 
379
 
    # tbzrcache executables - a "console" version for debugging and a
380
 
    # GUI version that is generally used.
381
 
    tbzrcache = dict(
382
 
        script = os.path.join(tbzr_root, "scripts", "tbzrcache.py"),
383
 
        icon_resources = icon_resources,
384
 
        other_resources = other_resources,
385
 
    )
386
 
    console_targets.append(tbzrcache)
387
 
 
388
 
    # Make a windows version which is the same except for the base name.
389
 
    tbzrcachew = tbzrcache.copy()
390
 
    tbzrcachew["dest_base"]="tbzrcachew"
391
 
    gui_targets.append(tbzrcachew)
392
 
 
393
 
    # ditto for the tbzrcommand tool
394
 
    tbzrcommand = dict(
395
 
        script = os.path.join(tbzr_root, "scripts", "tbzrcommand.py"),
396
 
        icon_resources = [(0,'bzr.ico')],
397
 
    )
398
 
    console_targets.append(tbzrcommand)
399
 
    tbzrcommandw = tbzrcommand.copy()
400
 
    tbzrcommandw["dest_base"]="tbzrcommandw"
401
 
    gui_targets.append(tbzrcommandw)
402
 
    
403
 
    # A utility to see python output from both C++ and Python based shell
404
 
    # extensions
405
 
    tracer = dict(script=os.path.join(tbzr_root, "scripts", "tbzrtrace.py"))
406
 
    console_targets.append(tracer)
407
 
 
408
 
    # The C++ implemented shell extensions.
409
 
    dist_dir = os.path.join(tbzr_root, "shellext", "build")
410
 
    data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x86.dll')]))
411
 
    data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x64.dll')]))
412
 
 
413
 
 
414
 
def get_qbzr_py2exe_info(includes, excludes, packages, data_files):
415
 
    # PyQt4 itself still escapes the plugin detection code for some reason...
416
 
    includes.append('PyQt4.QtCore')
417
 
    includes.append('PyQt4.QtGui')
418
 
    includes.append('sip') # extension module required for Qt.
419
 
    packages.append('pygments') # colorizer for qbzr
420
 
    packages.append('docutils') # html formatting
421
 
    includes.append('win32event')  # for qsubprocess stuff
422
 
    # the qt binaries might not be on PATH...
423
 
    # They seem to install to a place like C:\Python25\PyQt4\*
424
 
    # Which is not the same as C:\Python25\Lib\site-packages\PyQt4
425
 
    pyqt_dir = os.path.join(sys.prefix, "PyQt4")
426
 
    pyqt_bin_dir = os.path.join(pyqt_dir, "bin")
427
 
    if os.path.isdir(pyqt_bin_dir):
428
 
        path = os.environ.get("PATH", "")
429
 
        if pyqt_bin_dir.lower() not in [p.lower() for p in path.split(os.pathsep)]:
430
 
            os.environ["PATH"] = path + os.pathsep + pyqt_bin_dir
431
 
    # also add all imageformat plugins to distribution
432
 
    # We will look in 2 places, dirname(PyQt4.__file__) and pyqt_dir
433
 
    base_dirs_to_check = []
434
 
    if os.path.isdir(pyqt_dir):
435
 
        base_dirs_to_check.append(pyqt_dir)
436
 
    try:
437
 
        import PyQt4
438
 
    except ImportError:
439
 
        pass
440
 
    else:
441
 
        pyqt4_base_dir = os.path.dirname(PyQt4.__file__)
442
 
        if pyqt4_base_dir != pyqt_dir:
443
 
            base_dirs_to_check.append(pyqt4_base_dir)
444
 
    if not base_dirs_to_check:
445
 
        log.warn("Can't find PyQt4 installation -> not including imageformat"
446
 
                 " plugins")
447
 
    else:
448
 
        files = []
449
 
        for base_dir in base_dirs_to_check:
450
 
            plug_dir = os.path.join(base_dir, 'plugins', 'imageformats')
451
 
            if os.path.isdir(plug_dir):
452
 
                for fname in os.listdir(plug_dir):
453
 
                    # Include plugin dlls, but not debugging dlls
454
 
                    fullpath = os.path.join(plug_dir, fname)
455
 
                    if fname.endswith('.dll') and not fname.endswith('d4.dll'):
456
 
                        files.append(fullpath)
457
 
        if files:
458
 
            data_files.append(('imageformats', files))
459
 
        else:
460
 
            log.warn('PyQt4 was found, but we could not find any imageformat'
461
 
                     ' plugins. Are you sure your configuration is correct?')
462
 
 
463
 
 
464
 
def get_svn_py2exe_info(includes, excludes, packages):
465
 
    packages.append('subvertpy')
466
 
    packages.append('sqlite3')
467
 
 
468
 
 
469
 
if 'bdist_wininst' in sys.argv:
470
 
    def find_docs():
471
 
        docs = []
472
 
        for root, dirs, files in os.walk('doc'):
473
 
            r = []
474
 
            for f in files:
475
 
                if (os.path.splitext(f)[1] in ('.html','.css','.png','.pdf')
476
 
                    or f == 'quick-start-summary.svg'):
477
 
                    r.append(os.path.join(root, f))
478
 
            if r:
479
 
                relative = root[4:]
480
 
                if relative:
481
 
                    target = os.path.join('Doc\\Bazaar', relative)
482
 
                else:
483
 
                    target = 'Doc\\Bazaar'
484
 
                docs.append((target, r))
485
 
        return docs
486
 
 
487
 
    # python's distutils-based win32 installer
488
 
    ARGS = {'scripts': ['bzr', 'tools/win32/bzr-win32-bdist-postinstall.py'],
489
 
            'ext_modules': ext_modules,
490
 
            # help pages
491
 
            'data_files': find_docs(),
492
 
            # for building pyrex extensions
493
 
            'cmdclass': {'build_ext': build_ext_if_possible},
494
 
           }
495
 
 
496
 
    ARGS.update(META_INFO)
497
 
    ARGS.update(BZRLIB)
498
 
    ARGS.update(PKG_DATA)
499
 
    
500
 
    setup(**ARGS)
501
 
 
502
 
elif 'py2exe' in sys.argv:
503
 
    import glob
504
 
    # py2exe setup
505
 
    import py2exe
506
 
 
507
 
    # pick real bzr version
508
 
    import bzrlib
509
 
 
510
 
    version_number = []
511
 
    for i in bzrlib.version_info[:4]:
512
 
        try:
513
 
            i = int(i)
514
 
        except ValueError:
515
 
            i = 0
516
 
        version_number.append(str(i))
517
 
    version_str = '.'.join(version_number)
518
 
 
519
 
    # An override to install_data used only by py2exe builds, which arranges
520
 
    # to byte-compile any .py files in data_files (eg, our plugins)
521
 
    # Necessary as we can't rely on the user having the relevant permissions
522
 
    # to the "Program Files" directory to generate them on the fly.
523
 
    class install_data_with_bytecompile(install_data):
524
 
        def run(self):
525
 
            from distutils.util import byte_compile
526
 
 
527
 
            install_data.run(self)
528
 
 
529
 
            py2exe = self.distribution.get_command_obj('py2exe', False)
530
 
            # GZ 2010-04-19: Setup has py2exe.optimize as 2, but give plugins
531
 
            #                time before living with docstring stripping
532
 
            optimize = 1
533
 
            compile_names = [f for f in self.outfiles if f.endswith('.py')]
534
 
            # Round mtime to nearest even second so that installing on a FAT
535
 
            # filesystem bytecode internal and script timestamps will match
536
 
            for f in compile_names:
537
 
                mtime = os.stat(f).st_mtime
538
 
                remainder = mtime % 2
539
 
                if remainder:
540
 
                    mtime -= remainder
541
 
                    os.utime(f, (mtime, mtime))
542
 
            byte_compile(compile_names,
543
 
                         optimize=optimize,
544
 
                         force=self.force, prefix=self.install_dir,
545
 
                         dry_run=self.dry_run)
546
 
            self.outfiles.extend([f + 'o' for f in compile_names])
547
 
    # end of class install_data_with_bytecompile
548
 
 
549
 
    target = py2exe.build_exe.Target(script = "bzr",
550
 
                                     dest_base = "bzr",
551
 
                                     icon_resources = [(0,'bzr.ico')],
552
 
                                     name = META_INFO['name'],
553
 
                                     version = version_str,
554
 
                                     description = META_INFO['description'],
555
 
                                     author = META_INFO['author'],
556
 
                                     copyright = "(c) Canonical Ltd, 2005-2010",
557
 
                                     company_name = "Canonical Ltd.",
558
 
                                     comments = META_INFO['description'],
559
 
                                    )
560
 
 
561
 
    packages = BZRLIB['packages']
562
 
    packages.remove('bzrlib')
563
 
    packages = [i for i in packages if not i.startswith('bzrlib.plugins')]
564
 
    includes = []
565
 
    for i in glob.glob('bzrlib\\*.py'):
566
 
        module = i[:-3].replace('\\', '.')
567
 
        if module.endswith('__init__'):
568
 
            module = module[:-len('__init__')]
569
 
        includes.append(module)
570
 
 
571
 
    additional_packages = set()
572
 
    if sys.version.startswith('2.4'):
573
 
        # adding elementtree package
574
 
        additional_packages.add('elementtree')
575
 
    elif sys.version.startswith('2.6') or sys.version.startswith('2.5'):
576
 
        additional_packages.add('xml.etree')
577
 
    else:
578
 
        import warnings
579
 
        warnings.warn('Unknown Python version.\n'
580
 
                      'Please check setup.py script for compatibility.')
581
 
 
582
 
    # Although we currently can't enforce it, we consider it an error for
583
 
    # py2exe to report any files are "missing".  Such modules we know aren't
584
 
    # used should be listed here.
585
 
    excludes = """Tkinter psyco ElementPath r_hmac
586
 
                  ImaginaryModule cElementTree elementtree.ElementTree
587
 
                  Crypto.PublicKey._fastmath
588
 
                  medusa medusa.filesys medusa.ftp_server
589
 
                  tools
590
 
                  resource validate""".split()
591
 
    dll_excludes = []
592
 
 
593
 
    # email package from std python library use lazy import,
594
 
    # so we need to explicitly add all package
595
 
    additional_packages.add('email')
596
 
    # And it uses funky mappings to conver to 'Oldname' to 'newname'.  As
597
 
    # a result, packages like 'email.Parser' show as missing.  Tell py2exe
598
 
    # to exclude them.
599
 
    import email
600
 
    for oldname in getattr(email, '_LOWERNAMES', []):
601
 
        excludes.append("email." + oldname)
602
 
    for oldname in getattr(email, '_MIMENAMES', []):
603
 
        excludes.append("email.MIME" + oldname)
604
 
 
605
 
    # text files for help topis
606
 
    text_topics = glob.glob('bzrlib/help_topics/en/*.txt')
607
 
    topics_files = [('lib/help_topics/en', text_topics)]
608
 
 
609
 
    # built-in plugins
610
 
    plugins_files = []
611
 
    # XXX - should we consider having the concept of an 'official' build,
612
 
    # which hard-codes the list of plugins, gets more upset if modules are
613
 
    # missing, etc?
614
 
    plugins = None # will be a set after plugin sniffing...
615
 
    for root, dirs, files in os.walk('bzrlib/plugins'):
616
 
        if root == 'bzrlib/plugins':
617
 
            plugins = set(dirs)
618
 
            # We ship plugins as normal files on the file-system - however,
619
 
            # the build process can cause *some* of these plugin files to end
620
 
            # up in library.zip. Thus, we saw (eg) "plugins/svn/test" in
621
 
            # library.zip, and then saw import errors related to that as the
622
 
            # rest of the svn plugin wasn't. So we tell py2exe to leave the
623
 
            # plugins out of the .zip file
624
 
            excludes.extend(["bzrlib.plugins." + d for d in dirs])
625
 
        x = []
626
 
        for i in files:
627
 
            # Throw away files we don't want packaged. Note that plugins may
628
 
            # have data files with all sorts of extensions so we need to
629
 
            # be conservative here about what we ditch.
630
 
            ext = os.path.splitext(i)[1]
631
 
            if ext.endswith('~') or ext in [".pyc", ".swp"]:
632
 
                continue
633
 
            if i == '__init__.py' and root == 'bzrlib/plugins':
634
 
                continue
635
 
            x.append(os.path.join(root, i))
636
 
        if x:
637
 
            target_dir = root[len('bzrlib/'):]  # install to 'plugins/...'
638
 
            plugins_files.append((target_dir, x))
639
 
    # find modules for built-in plugins
640
 
    import tools.package_mf
641
 
    mf = tools.package_mf.CustomModuleFinder()
642
 
    mf.run_package('bzrlib/plugins')
643
 
    packs, mods = mf.get_result()
644
 
    additional_packages.update(packs)
645
 
    includes.extend(mods)
646
 
 
647
 
    console_targets = [target,
648
 
                       'tools/win32/bzr_postinstall.py',
649
 
                       ]
650
 
    gui_targets = []
651
 
    data_files = topics_files + plugins_files
652
 
 
653
 
    if 'qbzr' in plugins:
654
 
        get_qbzr_py2exe_info(includes, excludes, packages, data_files)
655
 
 
656
 
    if 'svn' in plugins:
657
 
        get_svn_py2exe_info(includes, excludes, packages)
658
 
 
659
 
    if "TBZR" in os.environ:
660
 
        # TORTOISE_OVERLAYS_MSI_WIN32 must be set to the location of the
661
 
        # TortoiseOverlays MSI installer file. It is in the TSVN svn repo and
662
 
        # can be downloaded from (username=guest, blank password):
663
 
        # http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays
664
 
        # look for: version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi
665
 
        # Ditto for TORTOISE_OVERLAYS_MSI_X64, pointing at *-x64.msi.
666
 
        for needed in ('TORTOISE_OVERLAYS_MSI_WIN32',
667
 
                       'TORTOISE_OVERLAYS_MSI_X64'):
668
 
            url = ('http://guest:@tortoisesvn.tigris.org/svn/tortoisesvn'
669
 
                   '/TortoiseOverlays')
670
 
            if not os.path.isfile(os.environ.get(needed, '<nofile>')):
671
 
                raise RuntimeError(
672
 
                    "\nPlease set %s to the location of the relevant"
673
 
                    "\nTortoiseOverlays .msi installer file."
674
 
                    " The installers can be found at"
675
 
                    "\n  %s"
676
 
                    "\ncheck in the version-X.Y.Z/bin/ subdir" % (needed, url))
677
 
        get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
678
 
                             gui_targets, data_files)
679
 
    else:
680
 
        # print this warning to stderr as output is redirected, so it is seen
681
 
        # at build time.  Also to stdout so it appears in the log
682
 
        for f in (sys.stderr, sys.stdout):
683
 
            f.write("Skipping TBZR binaries - "
684
 
                "please set TBZR to a directory to enable\n")
685
 
 
686
 
    # MSWSOCK.dll is a system-specific library, which py2exe accidentally pulls
687
 
    # in on Vista.
688
 
    dll_excludes.extend(["MSWSOCK.dll", "MSVCP60.dll", "powrprof.dll"])
689
 
    options_list = {"py2exe": {"packages": packages + list(additional_packages),
690
 
                               "includes": includes,
691
 
                               "excludes": excludes,
692
 
                               "dll_excludes": dll_excludes,
693
 
                               "dist_dir": "win32_bzr.exe",
694
 
                               "optimize": 2,
695
 
                              },
696
 
                   }
697
 
 
698
 
    # We want the libaray.zip to have optimize = 2, but the exe to have
699
 
    # optimize = 1, so that .py files that get compilied at run time
700
 
    # (e.g. user installed plugins) dont have their doc strings removed.
701
 
    class py2exe_no_oo_exe(py2exe.build_exe.py2exe):
702
 
        def build_executable(self, *args, **kwargs):
703
 
            self.optimize = 1
704
 
            py2exe.build_exe.py2exe.build_executable(self, *args, **kwargs)
705
 
            self.optimize = 2
706
 
 
707
 
    if __name__ == '__main__':
708
 
        setup(options=options_list,
709
 
              console=console_targets,
710
 
              windows=gui_targets,
711
 
              zipfile='lib/library.zip',
712
 
              data_files=data_files,
713
 
              cmdclass={'install_data': install_data_with_bytecompile,
714
 
                        'py2exe': py2exe_no_oo_exe},
715
 
              )
716
 
 
717
 
else:
718
 
    # ad-hoc for easy_install
719
 
    DATA_FILES = []
720
 
    if not 'bdist_egg' in sys.argv:
721
 
        # generate and install bzr.1 only with plain install, not the
722
 
        # easy_install one
723
 
        DATA_FILES = [('man/man1', ['bzr.1'])]
724
 
 
725
 
    if sys.platform != 'win32':
726
 
        # see https://wiki.kubuntu.org/Apport/DeveloperHowTo
727
 
        #
728
 
        # checking the paths and hardcoding the check for root is a bit gross,
729
 
        # but I don't see a cleaner way to find out the locations in a way
730
 
        # that's going to align with the hardcoded paths in apport.
731
 
        if os.geteuid() == 0:
732
 
            DATA_FILES += [
733
 
                ('/usr/share/apport/package-hooks',
734
 
                    ['apport/source_bzr.py']),
735
 
                ('/etc/apport/crashdb.conf.d/',
736
 
                    ['apport/bzr-crashdb.conf']),]
737
 
 
738
 
    # std setup
739
 
    ARGS = {'scripts': ['bzr'],
740
 
            'data_files': DATA_FILES,
741
 
            'cmdclass': command_classes,
742
 
            'ext_modules': ext_modules,
743
 
           }
744
 
 
745
 
    ARGS.update(META_INFO)
746
 
    ARGS.update(BZRLIB)
747
 
    ARGS.update(PKG_DATA)
748
 
 
749
 
    if __name__ == '__main__':
750
 
        setup(**ARGS)
 
8
 
 
9
setup(name='bzr',
 
10
      version='0.0.0',
 
11
      author='Martin Pool',
 
12
      author_email='mbp@sourcefrog.net',
 
13
      url='http://www.bazaar-ng.org/',
 
14
      description='Friendly distributed version control system',
 
15
      license='GNU GPL v2',
 
16
      packages=['bzrlib',
 
17
                'bzrlib.plugins',
 
18
                'bzrlib.selftest',
 
19
                'bzrlib.util',
 
20
                'bzrlib.util.elementtree',
 
21
                'bzrlib.util.effbot.org',
 
22
                'bzrlib.util.urlgrabber'],
 
23
      scripts=['bzr'])