~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: Martin Pool
  • Date: 2005-04-28 07:24:55 UTC
  • Revision ID: mbp@sourcefrog.net-20050428072453-7b99afa993a1e549
todo

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