148
173
########################
175
from bzrlib.bzr_distutils import build_mo
177
command_classes = {'install_scripts': my_install_scripts,
179
'build_mo': build_mo,
181
from distutils import log
182
from distutils.errors import CCompilerError, DistutilsPlatformError
183
from distutils.extension import Extension
187
from Cython.Distutils import build_ext
188
from Cython.Compiler.Version import version as pyrex_version
190
print("No Cython, trying Pyrex...")
191
from Pyrex.Distutils import build_ext
192
from Pyrex.Compiler.Version import version as pyrex_version
195
# try to build the extension from the prior generated source.
197
print("The python package 'Pyrex' is not available."
198
" If the .c files are available,")
199
print("they will be built,"
200
" but modifying the .pyx files will not rebuild them.")
202
from distutils.command.build_ext import build_ext
205
pyrex_version_info = tuple(map(int, pyrex_version.rstrip("+").split('.')))
208
class build_ext_if_possible(build_ext):
210
user_options = build_ext.user_options + [
211
('allow-python-fallback', None,
212
"When an extension cannot be built, allow falling"
213
" back to the pure-python implementation.")
216
def initialize_options(self):
217
build_ext.initialize_options(self)
218
self.allow_python_fallback = False
223
except DistutilsPlatformError:
224
e = sys.exc_info()[1]
225
if not self.allow_python_fallback:
226
log.warn('\n Cannot build extensions.\n'
227
' Use "build_ext --allow-python-fallback" to use'
228
' slower python implementations instead.\n')
231
log.warn('\n Extensions cannot be built.\n'
232
' Using the slower Python implementations instead.\n')
234
def build_extension(self, ext):
236
build_ext.build_extension(self, ext)
237
except CCompilerError:
238
if not self.allow_python_fallback:
239
log.warn('\n Cannot build extension "%s".\n'
240
' Use "build_ext --allow-python-fallback" to use'
241
' slower python implementations instead.\n'
244
log.warn('\n Building of "%s" extension failed.\n'
245
' Using the slower Python implementation instead.'
249
# Override the build_ext if we have Pyrex available
250
command_classes['build_ext'] = build_ext_if_possible
251
unavailable_files = []
254
def add_pyrex_extension(module_name, libraries=None, extra_source=[]):
255
"""Add a pyrex module to build.
257
This will use Pyrex to auto-generate the .c file if it is available.
258
Otherwise it will fall back on the .c file. If the .c file is not
259
available, it will warn, and not add anything.
261
You can pass any extra options to Extension through kwargs. One example is
264
:param module_name: The python path to the module. This will be used to
265
determine the .pyx and .c files to use.
267
path = module_name.replace('.', '/')
268
pyrex_name = path + '.pyx'
271
if sys.platform == 'win32':
272
# pyrex uses the macro WIN32 to detect the platform, even though it
273
# should be using something like _WIN32 or MS_WINDOWS, oh well, we can
274
# give it the right value.
275
define_macros.append(('WIN32', None))
277
source = [pyrex_name]
279
if not os.path.isfile(c_name):
280
unavailable_files.append(c_name)
284
source.extend(extra_source)
285
ext_modules.append(Extension(module_name, source,
286
define_macros=define_macros, libraries=libraries))
289
add_pyrex_extension('bzrlib._annotator_pyx')
290
add_pyrex_extension('bzrlib._bencode_pyx')
291
add_pyrex_extension('bzrlib._chunks_to_lines_pyx')
292
add_pyrex_extension('bzrlib._groupcompress_pyx',
293
extra_source=['bzrlib/diff-delta.c'])
294
add_pyrex_extension('bzrlib._knit_load_data_pyx')
295
add_pyrex_extension('bzrlib._known_graph_pyx')
296
add_pyrex_extension('bzrlib._rio_pyx')
297
if sys.platform == 'win32':
298
add_pyrex_extension('bzrlib._dirstate_helpers_pyx',
299
libraries=['Ws2_32'])
300
add_pyrex_extension('bzrlib._walkdirs_win32')
302
if have_pyrex and pyrex_version_info[:3] == (0,9,4):
303
# Pyrex 0.9.4.1 fails to compile this extension correctly
304
# The code it generates re-uses a "local" pointer and
305
# calls "PY_DECREF" after having set it to NULL. (It mixes PY_XDECREF
306
# which is NULL safe with PY_DECREF which is not.)
307
# <https://bugs.launchpad.net/bzr/+bug/449372>
308
# <https://bugs.launchpad.net/bzr/+bug/276868>
309
print('Cannot build extension "bzrlib._dirstate_helpers_pyx" using')
310
print('your version of pyrex "%s". Please upgrade your pyrex'
312
print('install. For now, the non-compiled (python) version will')
313
print('be used instead.')
315
add_pyrex_extension('bzrlib._dirstate_helpers_pyx')
316
add_pyrex_extension('bzrlib._readdir_pyx')
317
add_pyrex_extension('bzrlib._chk_map_pyx')
318
ext_modules.append(Extension('bzrlib._patiencediff_c',
319
['bzrlib/_patiencediff_c.c']))
320
if have_pyrex and pyrex_version_info < (0, 9, 6, 3):
322
print('Your Pyrex/Cython version %s is too old to build the simple_set' % (
324
print('and static_tuple extensions.')
325
print('Please upgrade to at least Pyrex 0.9.6.3')
327
# TODO: Should this be a fatal error?
329
# We only need 0.9.6.3 to build _simple_set_pyx, but static_tuple depends
331
add_pyrex_extension('bzrlib._simple_set_pyx')
332
ext_modules.append(Extension('bzrlib._static_tuple_c',
333
['bzrlib/_static_tuple_c.c']))
334
add_pyrex_extension('bzrlib._btree_serializer_pyx')
337
if unavailable_files:
338
print('C extension(s) not found:')
339
print(' %s' % ('\n '.join(unavailable_files),))
340
print('The python versions will be used instead.')
344
def get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
345
gui_targets, data_files):
346
packages.append('tbzrcommands')
348
# ModuleFinder can't handle runtime changes to __path__, but
349
# win32com uses them. Hook this in so win32com.shell is found.
352
import cPickle as pickle
353
for p in win32com.__path__[1:]:
354
modulefinder.AddPackagePath("win32com", p)
355
for extra in ["win32com.shell"]:
357
m = sys.modules[extra]
358
for p in m.__path__[1:]:
359
modulefinder.AddPackagePath(extra, p)
361
# TBZR points to the TBZR directory
362
tbzr_root = os.environ["TBZR"]
364
# Ensure tbzrlib itself is on sys.path
365
sys.path.append(tbzr_root)
367
packages.append("tbzrlib")
369
# collect up our icons.
371
ico_root = os.path.join(tbzr_root, 'tbzrlib', 'resources')
372
icos = [] # list of (path_root, relative_ico_path)
373
# First always bzr's icon and its in the root of the bzr tree.
374
icos.append(('', 'bzr.ico'))
375
for root, dirs, files in os.walk(ico_root):
376
icos.extend([(ico_root, os.path.join(root, f)[len(ico_root)+1:])
377
for f in files if f.endswith('.ico')])
378
# allocate an icon ID for each file and the full path to the ico
379
icon_resources = [(rid, os.path.join(ico_dir, ico_name))
380
for rid, (ico_dir, ico_name) in enumerate(icos)]
381
# create a string resource with the mapping. Might as well save the
382
# runtime some effort and write a pickle.
383
# Runtime expects unicode objects with forward-slash seps.
384
fse = sys.getfilesystemencoding()
385
map_items = [(f.replace('\\', '/').decode(fse), rid)
386
for rid, (_, f) in enumerate(icos)]
387
ico_map = dict(map_items)
388
# Create a new resource type of 'ICON_MAP', and use ID=1
389
other_resources = [ ("ICON_MAP", 1, pickle.dumps(ico_map))]
391
excludes.extend("""pywin pywin.dialogs pywin.dialogs.list
392
win32ui crawler.Crawler""".split())
394
# tbzrcache executables - a "console" version for debugging and a
395
# GUI version that is generally used.
397
script = os.path.join(tbzr_root, "scripts", "tbzrcache.py"),
398
icon_resources = icon_resources,
399
other_resources = other_resources,
401
console_targets.append(tbzrcache)
403
# Make a windows version which is the same except for the base name.
404
tbzrcachew = tbzrcache.copy()
405
tbzrcachew["dest_base"]="tbzrcachew"
406
gui_targets.append(tbzrcachew)
408
# ditto for the tbzrcommand tool
410
script = os.path.join(tbzr_root, "scripts", "tbzrcommand.py"),
411
icon_resources = icon_resources,
412
other_resources = other_resources,
414
console_targets.append(tbzrcommand)
415
tbzrcommandw = tbzrcommand.copy()
416
tbzrcommandw["dest_base"]="tbzrcommandw"
417
gui_targets.append(tbzrcommandw)
419
# A utility to see python output from both C++ and Python based shell
421
tracer = dict(script=os.path.join(tbzr_root, "scripts", "tbzrtrace.py"))
422
console_targets.append(tracer)
424
# The C++ implemented shell extensions.
425
dist_dir = os.path.join(tbzr_root, "shellext", "build")
426
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x86.dll')]))
427
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x64.dll')]))
430
def get_qbzr_py2exe_info(includes, excludes, packages, data_files):
431
# PyQt4 itself still escapes the plugin detection code for some reason...
432
includes.append('PyQt4.QtCore')
433
includes.append('PyQt4.QtGui')
434
includes.append('PyQt4.QtTest')
435
includes.append('sip') # extension module required for Qt.
436
packages.append('pygments') # colorizer for qbzr
437
packages.append('docutils') # html formatting
438
includes.append('win32event') # for qsubprocess stuff
439
# the qt binaries might not be on PATH...
440
# They seem to install to a place like C:\Python25\PyQt4\*
441
# Which is not the same as C:\Python25\Lib\site-packages\PyQt4
442
pyqt_dir = os.path.join(sys.prefix, "PyQt4")
443
pyqt_bin_dir = os.path.join(pyqt_dir, "bin")
444
if os.path.isdir(pyqt_bin_dir):
445
path = os.environ.get("PATH", "")
446
if pyqt_bin_dir.lower() not in [p.lower() for p in path.split(os.pathsep)]:
447
os.environ["PATH"] = path + os.pathsep + pyqt_bin_dir
448
# also add all imageformat plugins to distribution
449
# We will look in 2 places, dirname(PyQt4.__file__) and pyqt_dir
450
base_dirs_to_check = []
451
if os.path.isdir(pyqt_dir):
452
base_dirs_to_check.append(pyqt_dir)
458
pyqt4_base_dir = os.path.dirname(PyQt4.__file__)
459
if pyqt4_base_dir != pyqt_dir:
460
base_dirs_to_check.append(pyqt4_base_dir)
461
if not base_dirs_to_check:
462
log.warn("Can't find PyQt4 installation -> not including imageformat"
466
for base_dir in base_dirs_to_check:
467
plug_dir = os.path.join(base_dir, 'plugins', 'imageformats')
468
if os.path.isdir(plug_dir):
469
for fname in os.listdir(plug_dir):
470
# Include plugin dlls, but not debugging dlls
471
fullpath = os.path.join(plug_dir, fname)
472
if fname.endswith('.dll') and not fname.endswith('d4.dll'):
473
files.append(fullpath)
475
data_files.append(('imageformats', files))
477
log.warn('PyQt4 was found, but we could not find any imageformat'
478
' plugins. Are you sure your configuration is correct?')
481
def get_svn_py2exe_info(includes, excludes, packages):
482
packages.append('subvertpy')
483
packages.append('sqlite3')
486
def get_git_py2exe_info(includes, excludes, packages):
487
packages.append('dulwich')
490
def get_fastimport_py2exe_info(includes, excludes, packages):
491
# This is the python-fastimport package, not to be confused with the
492
# bzr-fastimport plugin.
493
packages.append('fastimport')
150
496
if 'bdist_wininst' in sys.argv:
153
docs = glob.glob('doc/*.htm') + ['doc/default.css']
499
for root, dirs, files in os.walk('doc'):
502
if (os.path.splitext(f)[1] in ('.html','.css','.png','.pdf')
503
or f == 'quick-start-summary.svg'):
504
r.append(os.path.join(root, f))
508
target = os.path.join('Doc\\Bazaar', relative)
510
target = 'Doc\\Bazaar'
511
docs.append((target, r))
154
514
# python's distutils-based win32 installer
155
515
ARGS = {'scripts': ['bzr', 'tools/win32/bzr-win32-bdist-postinstall.py'],
516
'ext_modules': ext_modules,
157
'data_files': [('Doc/Bazaar', docs)],
518
'data_files': find_docs(),
519
# for building pyrex extensions
520
'cmdclass': command_classes,
160
523
ARGS.update(META_INFO)
161
524
ARGS.update(BZRLIB)
525
PKG_DATA['package_data']['bzrlib'].append('locale/*/LC_MESSAGES/*.mo')
162
526
ARGS.update(PKG_DATA)
166
530
elif 'py2exe' in sys.argv:
186
580
version = version_str,
187
581
description = META_INFO['description'],
188
582
author = META_INFO['author'],
189
copyright = "(c) Canonical Ltd, 2005-2007",
583
copyright = "(c) Canonical Ltd, 2005-2010",
190
584
company_name = "Canonical Ltd.",
191
585
comments = META_INFO['description'],
194
additional_packages = []
587
gui_target = copy.copy(target)
588
gui_target.dest_base = "bzrw"
590
packages = BZRLIB['packages']
591
packages.remove('bzrlib')
592
packages = [i for i in packages if not i.startswith('bzrlib.plugins')]
594
for i in glob.glob('bzrlib\\*.py'):
595
module = i[:-3].replace('\\', '.')
596
if module.endswith('__init__'):
597
module = module[:-len('__init__')]
598
includes.append(module)
600
additional_packages = set()
195
601
if sys.version.startswith('2.4'):
196
602
# adding elementtree package
197
additional_packages.append('elementtree')
198
elif sys.version.startswith('2.5'):
199
additional_packages.append('xml.etree')
603
additional_packages.add('elementtree')
604
elif sys.version.startswith('2.6') or sys.version.startswith('2.5'):
605
additional_packages.add('xml.etree')
202
608
warnings.warn('Unknown Python version.\n'
203
609
'Please check setup.py script for compatibility.')
205
options_list = {"py2exe": {"packages": BZRLIB['packages'] +
207
"excludes": ["Tkinter", "medusa"],
611
# Although we currently can't enforce it, we consider it an error for
612
# py2exe to report any files are "missing". Such modules we know aren't
613
# used should be listed here.
614
excludes = """Tkinter psyco ElementPath r_hmac
615
ImaginaryModule cElementTree elementtree.ElementTree
616
Crypto.PublicKey._fastmath
617
medusa medusa.filesys medusa.ftp_server
619
resource validate""".split()
622
# email package from std python library use lazy import,
623
# so we need to explicitly add all package
624
additional_packages.add('email')
625
# And it uses funky mappings to conver to 'Oldname' to 'newname'. As
626
# a result, packages like 'email.Parser' show as missing. Tell py2exe
629
for oldname in getattr(email, '_LOWERNAMES', []):
630
excludes.append("email." + oldname)
631
for oldname in getattr(email, '_MIMENAMES', []):
632
excludes.append("email.MIME" + oldname)
634
# text files for help topis
635
text_topics = glob.glob('bzrlib/help_topics/en/*.txt')
636
topics_files = [('lib/help_topics/en', text_topics)]
640
# XXX - should we consider having the concept of an 'official' build,
641
# which hard-codes the list of plugins, gets more upset if modules are
643
plugins = None # will be a set after plugin sniffing...
644
for root, dirs, files in os.walk('bzrlib/plugins'):
645
if root == 'bzrlib/plugins':
647
# We ship plugins as normal files on the file-system - however,
648
# the build process can cause *some* of these plugin files to end
649
# up in library.zip. Thus, we saw (eg) "plugins/svn/test" in
650
# library.zip, and then saw import errors related to that as the
651
# rest of the svn plugin wasn't. So we tell py2exe to leave the
652
# plugins out of the .zip file
653
excludes.extend(["bzrlib.plugins." + d for d in dirs])
656
# Throw away files we don't want packaged. Note that plugins may
657
# have data files with all sorts of extensions so we need to
658
# be conservative here about what we ditch.
659
ext = os.path.splitext(i)[1]
660
if ext.endswith('~') or ext in [".pyc", ".swp"]:
662
if i == '__init__.py' and root == 'bzrlib/plugins':
664
x.append(os.path.join(root, i))
666
target_dir = root[len('bzrlib/'):] # install to 'plugins/...'
667
plugins_files.append((target_dir, x))
668
# find modules for built-in plugins
669
import tools.package_mf
670
mf = tools.package_mf.CustomModuleFinder()
671
mf.run_package('bzrlib/plugins')
672
packs, mods = mf.get_result()
673
additional_packages.update(packs)
674
includes.extend(mods)
676
console_targets = [target,
677
'tools/win32/bzr_postinstall.py',
679
gui_targets = [gui_target]
680
data_files = topics_files + plugins_files + I18N_FILES
682
if 'qbzr' in plugins:
683
get_qbzr_py2exe_info(includes, excludes, packages, data_files)
686
get_svn_py2exe_info(includes, excludes, packages)
689
get_git_py2exe_info(includes, excludes, packages)
691
if 'fastimport' in plugins:
692
get_fastimport_py2exe_info(includes, excludes, packages)
694
if "TBZR" in os.environ:
695
# TORTOISE_OVERLAYS_MSI_WIN32 must be set to the location of the
696
# TortoiseOverlays MSI installer file. It is in the TSVN svn repo and
697
# can be downloaded from (username=guest, blank password):
698
# http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays
699
# look for: version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi
700
# Ditto for TORTOISE_OVERLAYS_MSI_X64, pointing at *-x64.msi.
701
for needed in ('TORTOISE_OVERLAYS_MSI_WIN32',
702
'TORTOISE_OVERLAYS_MSI_X64'):
703
url = ('http://guest:@tortoisesvn.tigris.org/svn/tortoisesvn'
705
if not os.path.isfile(os.environ.get(needed, '<nofile>')):
707
"\nPlease set %s to the location of the relevant"
708
"\nTortoiseOverlays .msi installer file."
709
" The installers can be found at"
711
"\ncheck in the version-X.Y.Z/bin/ subdir" % (needed, url))
712
get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
713
gui_targets, data_files)
715
# print this warning to stderr as output is redirected, so it is seen
716
# at build time. Also to stdout so it appears in the log
717
for f in (sys.stderr, sys.stdout):
718
f.write("Skipping TBZR binaries - "
719
"please set TBZR to a directory to enable\n")
721
# MSWSOCK.dll is a system-specific library, which py2exe accidentally pulls
723
dll_excludes.extend(["MSWSOCK.dll",
728
options_list = {"py2exe": {"packages": packages + list(additional_packages),
729
"includes": includes,
730
"excludes": excludes,
731
"dll_excludes": dll_excludes,
208
732
"dist_dir": "win32_bzr.exe",
734
"custom_boot_script":
735
"tools/win32/py2exe_boot_common.py",
211
setup(options=options_list,
213
'tools/win32/bzr_postinstall.py',
215
zipfile='lib/library.zip')
739
# We want the libaray.zip to have optimize = 2, but the exe to have
740
# optimize = 1, so that .py files that get compilied at run time
741
# (e.g. user installed plugins) dont have their doc strings removed.
742
class py2exe_no_oo_exe(py2exe.build_exe.py2exe):
743
def build_executable(self, *args, **kwargs):
745
py2exe.build_exe.py2exe.build_executable(self, *args, **kwargs)
748
if __name__ == '__main__':
749
command_classes['install_data'] = install_data_with_bytecompile
750
command_classes['py2exe'] = py2exe_no_oo_exe
751
setup(options=options_list,
752
console=console_targets,
754
zipfile='lib/library.zip',
755
data_files=data_files,
756
cmdclass=command_classes,
760
# ad-hoc for easy_install
762
if not 'bdist_egg' in sys.argv:
763
# generate and install bzr.1 only with plain install, not the
765
DATA_FILES = [('man/man1', ['bzr.1'])]
767
DATA_FILES = DATA_FILES + I18N_FILES
219
769
ARGS = {'scripts': ['bzr'],
220
'data_files': [('man/man1', ['bzr.1'])],
221
'cmdclass': {'build': bzr_build,
222
'install_scripts': my_install_scripts,
770
'data_files': DATA_FILES,
771
'cmdclass': command_classes,
772
'ext_modules': ext_modules,
226
775
ARGS.update(META_INFO)
227
776
ARGS.update(BZRLIB)
228
777
ARGS.update(PKG_DATA)
779
if __name__ == '__main__':