/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-05-07 13:19:31 UTC
  • mfrom: (6929.14.2 lossy)
  • Revision ID: breezy.the.bot@gmail.com-20180507131931-7wzw41zl4vegb1le
Add a --lossy option to push.

Merged from https://code.launchpad.net/~jelmer/brz/lossy-push/+merge/345125

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