/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: 2018-08-20 22:50:42 UTC
  • mfrom: (7067.3.1 fix-spurious)
  • Revision ID: breezy.the.bot@gmail.com-20180820225042-oqt9y92xn3az7drc
Fix a spuriously failing test.

Merged from https://code.launchpad.net/~jelmer/brz/fix-spurious/+merge/353457

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