~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to setup.py

(Mark Hammond) Updates to setup.py to support bundling tortoisebzr
        and qbzr into the standalone win32 installer.

Show diffs side-by-side

added added

removed removed

Lines of Context:
95
95
 
96
96
from distutils.core import setup
97
97
from distutils.command.install_scripts import install_scripts
 
98
from distutils.command.install_data import install_data
98
99
from distutils.command.build import build
99
100
 
100
101
###############################
242
243
    print
243
244
 
244
245
 
 
246
def get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
 
247
                         gui_targets):
 
248
    packages.append('tbzrcommands')
 
249
 
 
250
    # ModuleFinder can't handle runtime changes to __path__, but
 
251
    # win32com uses them.  Hook this in so win32com.shell is found.
 
252
    import modulefinder
 
253
    import win32com
 
254
    for p in win32com.__path__[1:]:
 
255
        modulefinder.AddPackagePath("win32com", p)
 
256
    for extra in ["win32com.shell"]:
 
257
        __import__(extra)
 
258
        m = sys.modules[extra]
 
259
        for p in m.__path__[1:]:
 
260
            modulefinder.AddPackagePath(extra, p)
 
261
 
 
262
    # TBZR points to the TBZR directory
 
263
    tbzr_root = os.environ["TBZR"]
 
264
 
 
265
    # Ensure tbzrlib itself is on sys.path
 
266
    sys.path.append(tbzr_root)
 
267
 
 
268
    # Ensure our COM "entry-point" is on sys.path
 
269
    sys.path.append(os.path.join(tbzr_root, "shellext", "python"))
 
270
 
 
271
    packages.append("tbzrlib")
 
272
    excludes.extend("""pywin pywin.dialogs pywin.dialogs.list
 
273
                       win32ui crawler.Crawler""".split())
 
274
 
 
275
    tbzr = dict(
 
276
        modules=["tbzr"],
 
277
        create_exe = False, # we only want a .dll
 
278
    )
 
279
    com_targets.append(tbzr)
 
280
 
 
281
    # tbzrcache executables - a "console" version for debugging and a
 
282
    # GUI version that is generally used.
 
283
    tbzrcache = dict(
 
284
        script = os.path.join(tbzr_root, "Scripts", "tbzrcache.py"),
 
285
        icon_resources = [(0,'bzr.ico')],
 
286
    )
 
287
    console_targets.append(tbzrcache)
 
288
 
 
289
    # Make a windows version which is the same except for the base name.
 
290
    tbzrcachew = tbzrcache.copy()
 
291
    tbzrcachew["dest_base"]="tbzrcachew"
 
292
    gui_targets.append(tbzrcachew)
 
293
 
 
294
    # ditto for the tbzrcommand tool
 
295
    tbzrcommand = dict(
 
296
        script = os.path.join(tbzr_root, "Scripts", "tbzrcommand.py"),
 
297
        icon_resources = [(0,'bzr.ico')],
 
298
    )
 
299
    console_targets.append(tbzrcommand)
 
300
    tbzrcommandw = tbzrcommand.copy()
 
301
    tbzrcommandw["dest_base"]="tbzrcommandw"
 
302
    gui_targets.append(tbzrcommandw)
 
303
    
 
304
    # tbzr tests
 
305
    tbzrtest = dict(
 
306
        script = os.path.join(tbzr_root, "Scripts", "tbzrtest.py"),
 
307
    )
 
308
    console_targets.append(tbzrtest)
 
309
 
 
310
    # A utility to see python output from the shell extension - this will
 
311
    # die when we get a c++ extension
 
312
    # any .py file from pywin32's win32 lib will do (other than
 
313
    # win32traceutil itself that is)
 
314
    import winerror
 
315
    win32_lib_dir = os.path.dirname(winerror.__file__)
 
316
    tracer = dict(script = os.path.join(win32_lib_dir, "win32traceutil.py"),
 
317
                  dest_base="tbzr_tracer")
 
318
    console_targets.append(tracer)
 
319
 
 
320
 
 
321
def get_qbzr_py2exe_info(includes, excludes, packages):
 
322
    # PyQt4 itself still escapes the plugin detection code for some reason...
 
323
    packages.append('PyQt4')
 
324
    excludes.append('PyQt4.elementtree.ElementTree')
 
325
    includes.append('sip') # extension module required for Qt.
 
326
    packages.append('pygments') # colorizer for qbzr
 
327
    # but we can avoid many Qt4 Dlls.
 
328
    dll_excludes.extend(
 
329
        """QtAssistantClient4.dll QtCLucene4.dll QtDesigner4.dll
 
330
        QtHelp4.dll QtNetwork4.dll QtOpenGL4.dll QtScript4.dll
 
331
        QtSql4.dll QtTest4.dll QtWebKit4.dll QtXml4.dll
 
332
        qscintilla2.dll""".split())
 
333
    # the qt binaries might not be on PATH...
 
334
    qt_dir = os.path.join(sys.prefix, "PyQt4", "bin")
 
335
    path = os.environ.get("PATH","")
 
336
    if qt_dir.lower() not in [p.lower() for p in path.split(os.pathsep)]:
 
337
        os.environ["PATH"] = path + os.pathsep + qt_dir
 
338
 
 
339
 
245
340
if 'bdist_wininst' in sys.argv:
246
341
    def find_docs():
247
342
        docs = []
292
387
        version_number.append(str(i))
293
388
    version_str = '.'.join(version_number)
294
389
 
 
390
    # An override to install_data used only by py2exe builds, which arranges
 
391
    # to byte-compile any .py files in data_files (eg, our plugins)
 
392
    # Necessary as we can't rely on the user having the relevant permissions
 
393
    # to the "Program Files" directory to generate them on the fly.
 
394
    class install_data_with_bytecompile(install_data):
 
395
        def run(self):
 
396
            from distutils.util import byte_compile
 
397
 
 
398
            install_data.run(self)
 
399
 
 
400
            py2exe = self.distribution.get_command_obj('py2exe', False)
 
401
            optimize = py2exe.optimize
 
402
            compile_names = [f for f in self.outfiles if f.endswith('.py')]
 
403
            byte_compile(compile_names,
 
404
                         optimize=optimize,
 
405
                         force=self.force, prefix=self.install_dir,
 
406
                         dry_run=self.dry_run)
 
407
            if optimize:
 
408
                suffix = 'o'
 
409
            else:
 
410
                suffix = 'c'
 
411
            self.outfiles.extend([f + suffix for f in compile_names])
 
412
    # end of class install_data_with_bytecompile
 
413
 
295
414
    target = py2exe.build_exe.Target(script = "bzr",
296
415
                                     dest_base = "bzr",
297
416
                                     icon_resources = [(0,'bzr.ico')],
324
443
        import warnings
325
444
        warnings.warn('Unknown Python version.\n'
326
445
                      'Please check setup.py script for compatibility.')
 
446
 
 
447
    # Although we currently can't enforce it, we consider it an error for
 
448
    # py2exe to report any files are "missing".  Such modules we know aren't
 
449
    # used should be listed here.
 
450
    excludes = """Tkinter psyco ElementPath r_hmac
 
451
                  ImaginaryModule cElementTree elementtree.ElementTree
 
452
                  Crypto.PublicKey._fastmath
 
453
                  medusa medusa.filesys medusa.ftp_server
 
454
                  tools tools.doc_generate
 
455
                  resource validate""".split()
 
456
    dll_excludes = []
 
457
 
327
458
    # email package from std python library use lazy import,
328
459
    # so we need to explicitly add all package
329
460
    additional_packages.add('email')
 
461
    # And it uses funky mappings to conver to 'Oldname' to 'newname'.  As
 
462
    # a result, packages like 'email.Parser' show as missing.  Tell py2exe
 
463
    # to exclude them.
 
464
    import email
 
465
    for oldname in getattr(email, '_LOWERNAMES', []):
 
466
        excludes.append("email." + oldname)
 
467
    for oldname in getattr(email, '_MIMENAMES', []):
 
468
        excludes.append("email.MIME" + oldname)
330
469
 
331
470
    # text files for help topis
332
471
    text_topics = glob.glob('bzrlib/help_topics/en/*.txt')
334
473
 
335
474
    # built-in plugins
336
475
    plugins_files = []
 
476
    # XXX - should we consider having the concept of an 'official' build,
 
477
    # which hard-codes the list of plugins, gets more upset if modules are
 
478
    # missing, etc?
 
479
    plugins = None # will be a set after plugin sniffing...
337
480
    for root, dirs, files in os.walk('bzrlib/plugins'):
 
481
        if root == 'bzrlib/plugins':
 
482
            plugins = set(dirs)
338
483
        x = []
339
484
        for i in files:
340
 
            if not i.endswith('.py'):
 
485
            if os.path.splitext(i)[1] not in [".py", ".pyd", ".dll"]:
341
486
                continue
342
487
            if i == '__init__.py' and root == 'bzrlib/plugins':
343
488
                continue
351
496
    mf.run_package('bzrlib/plugins')
352
497
    packs, mods = mf.get_result()
353
498
    additional_packages.update(packs)
 
499
    includes.extend(mods)
 
500
 
 
501
    console_targets = [target,
 
502
                       'tools/win32/bzr_postinstall.py',
 
503
                       ]
 
504
    gui_targets = []
 
505
    com_targets = []
 
506
 
 
507
    if 'qbzr' in plugins:
 
508
        get_qbzr_py2exe_info(includes, excludes, packages)
 
509
 
 
510
    if "TBZR" in os.environ:
 
511
        # TORTOISE_OVERLAYS_MSI_WIN32 must be set to the location of the
 
512
        # TortoiseOverlays MSI installer file. It is in the TSVN svn repo and
 
513
        # can be downloaded from (username=guest, blank password):
 
514
        # http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays/version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi
 
515
        if not os.path.isfile(os.environ.get('TORTOISE_OVERLAYS_MSI_WIN32',
 
516
                                             '<nofile>')):
 
517
            raise RuntimeError("Please set TORTOISE_OVERLAYS_MSI_WIN32 to the"
 
518
                               " location of the Win32 TortoiseOverlays .msi"
 
519
                               " installer file")
 
520
        get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
 
521
                             gui_targets)
 
522
    else:
 
523
        # print this warning to stderr as output is redirected, so it is seen
 
524
        # at build time.  Also to stdout so it appears in the log
 
525
        for f in (sys.stderr, sys.stdout):
 
526
            print >> f, \
 
527
                "Skipping TBZR binaries - please set TBZR to a directory to enable"
354
528
 
355
529
    # MSWSOCK.dll is a system-specific library, which py2exe accidentally pulls
356
530
    # in on Vista.
 
531
    dll_excludes.append("MSWSOCK.dll")
357
532
    options_list = {"py2exe": {"packages": packages + list(additional_packages),
358
 
                               "includes": includes + mods,
359
 
                               "excludes": ["Tkinter", "medusa", "tools"],
360
 
                               "dll_excludes": ["MSWSOCK.dll"],
 
533
                               "includes": includes,
 
534
                               "excludes": excludes,
 
535
                               "dll_excludes": dll_excludes,
361
536
                               "dist_dir": "win32_bzr.exe",
 
537
                               "optimize": 1,
362
538
                              },
363
539
                   }
 
540
 
364
541
    setup(options=options_list,
365
 
          console=[target,
366
 
                   'tools/win32/bzr_postinstall.py',
367
 
                  ],
 
542
          console=console_targets,
 
543
          windows=gui_targets,
 
544
          com_server=com_targets,
368
545
          zipfile='lib/library.zip',
369
546
          data_files=topics_files + plugins_files,
 
547
          cmdclass={'install_data': install_data_with_bytecompile},
370
548
          )
371
549
 
372
550
else: