/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-01-01 23:55:19 UTC
  • mfrom: (7211.12.2 fast-export-default-out)
  • Revision ID: breezy.the.bot@gmail.com-20190101235519-s3qiot9brigweze2
Properly unwrap sys.stdout when writing a fast-export stream.

Merged from https://code.launchpad.net/~jelmer/brz/fast-export-default-out/+merge/359558

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