/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: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

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