/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to setup.py

(spiv) Fix edge cases in handling interrupts during _rename_in_limbo.
 (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

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