/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

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2019-07-07 19:22:03 UTC
  • mfrom: (7358.8.5 diff-binary-weird)
  • Revision ID: breezy.the.bot@gmail.com-20190707192203-n32v0wih963qdi6i
Don't include datestamps in filenames when reporting on binary files.

Merged from https://code.launchpad.net/~jelmer/brz/diff-binary-weird/+merge/369474

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