/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-09-13 12:30:11 UTC
  • mfrom: (7104.2.1 more-git-errors)
  • Revision ID: breezy.the.bot@gmail.com-20180913123011-e2g5v3in9p1m9nin
Handle the Launchpad way of saying "Repository not found".

Merged from https://code.launchpad.net/~jelmer/brz/more-git-errors/+merge/354801

Show diffs side-by-side

added added

removed removed

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