47
114
Create bzr.bat for win32.
53
117
install_scripts.run(self) # standard action
55
119
if sys.platform == "win32":
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"
121
scripts_dir = os.path.join(sys.prefix, 'Scripts')
122
script_path = self._quoted_path(os.path.join(scripts_dir,
124
python_exe = self._quoted_path(sys.executable)
125
args = self._win_batch_args()
126
batch_str = "@%s %s %s" % (python_exe, script_path, args)
127
batch_path = os.path.join(self.install_dir, "bzr.bat")
61
128
f = file(batch_path, "w")
62
129
f.write(batch_str)
64
print "Created:", batch_path
66
print "ERROR: Unable to create %s: %s" % (batch_path, e)
131
print("Created: %s" % batch_path)
133
e = sys.exc_info()[1]
134
print("ERROR: Unable to create %s: %s" % (batch_path, e))
136
def _quoted_path(self, path):
138
return '"' + path + '"'
142
def _win_batch_args(self):
143
from bzrlib.win32utils import winver
144
if winver == 'Windows NT':
147
return '%1 %2 %3 %4 %5 %6 %7 %8 %9'
148
#/class my_install_scripts
69
151
class bzr_build(build):
70
152
"""Customized build distutils action.
156
sub_commands = build.sub_commands + [
157
('build_mo', lambda _: True),
163
from tools import generate_docs
77
164
generate_docs.main(argv=["bzr", "man"])
79
167
########################
81
169
########################
86
author_email='mbp@sourcefrog.net',
87
url='http://www.bazaar-ng.org/',
88
description='Friendly distributed version control system',
96
'bzrlib.store.revision',
97
'bzrlib.store.versioned',
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',
108
'bzrlib.transport.http',
111
'bzrlib.util.elementtree',
112
'bzrlib.util.effbot.org',
113
'bzrlib.util.configobj',
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.
171
from tools.build_mo import build_mo
173
command_classes = {'install_scripts': my_install_scripts,
175
'build_mo': build_mo,
177
from distutils import log
178
from distutils.errors import CCompilerError, DistutilsPlatformError
179
from distutils.extension import Extension
183
from Cython.Distutils import build_ext
184
from Cython.Compiler.Version import version as pyrex_version
186
print("No Cython, trying Pyrex...")
187
from Pyrex.Distutils import build_ext
188
from Pyrex.Compiler.Version import version as pyrex_version
191
# try to build the extension from the prior generated source.
193
print("The python package 'Pyrex' is not available."
194
" If the .c files are available,")
195
print("they will be built,"
196
" but modifying the .pyx files will not rebuild them.")
198
from distutils.command.build_ext import build_ext
201
pyrex_version_info = tuple(map(int, pyrex_version.split('.')))
204
class build_ext_if_possible(build_ext):
206
user_options = build_ext.user_options + [
207
('allow-python-fallback', None,
208
"When an extension cannot be built, allow falling"
209
" back to the pure-python implementation.")
212
def initialize_options(self):
213
build_ext.initialize_options(self)
214
self.allow_python_fallback = False
219
except DistutilsPlatformError:
220
e = sys.exc_info()[1]
221
if not self.allow_python_fallback:
222
log.warn('\n Cannot build extensions.\n'
223
' Use "build_ext --allow-python-fallback" to use'
224
' slower python implementations instead.\n')
227
log.warn('\n Extensions cannot be built.\n'
228
' Using the slower Python implementations instead.\n')
230
def build_extension(self, ext):
232
build_ext.build_extension(self, ext)
233
except CCompilerError:
234
if not self.allow_python_fallback:
235
log.warn('\n Cannot build extension "%s".\n'
236
' Use "build_ext --allow-python-fallback" to use'
237
' slower python implementations instead.\n'
240
log.warn('\n Building of "%s" extension failed.\n'
241
' Using the slower Python implementation instead.'
245
# Override the build_ext if we have Pyrex available
246
command_classes['build_ext'] = build_ext_if_possible
247
unavailable_files = []
250
def add_pyrex_extension(module_name, libraries=None, extra_source=[]):
251
"""Add a pyrex module to build.
253
This will use Pyrex to auto-generate the .c file if it is available.
254
Otherwise it will fall back on the .c file. If the .c file is not
255
available, it will warn, and not add anything.
257
You can pass any extra options to Extension through kwargs. One example is
260
:param module_name: The python path to the module. This will be used to
261
determine the .pyx and .c files to use.
263
path = module_name.replace('.', '/')
264
pyrex_name = path + '.pyx'
267
if sys.platform == 'win32':
268
# pyrex uses the macro WIN32 to detect the platform, even though it
269
# should be using something like _WIN32 or MS_WINDOWS, oh well, we can
270
# give it the right value.
271
define_macros.append(('WIN32', None))
273
source = [pyrex_name]
275
if not os.path.isfile(c_name):
276
unavailable_files.append(c_name)
280
source.extend(extra_source)
281
ext_modules.append(Extension(module_name, source,
282
define_macros=define_macros, libraries=libraries))
285
add_pyrex_extension('bzrlib._annotator_pyx')
286
add_pyrex_extension('bzrlib._bencode_pyx')
287
add_pyrex_extension('bzrlib._chunks_to_lines_pyx')
288
add_pyrex_extension('bzrlib._groupcompress_pyx',
289
extra_source=['bzrlib/diff-delta.c'])
290
add_pyrex_extension('bzrlib._knit_load_data_pyx')
291
add_pyrex_extension('bzrlib._known_graph_pyx')
292
add_pyrex_extension('bzrlib._rio_pyx')
293
if sys.platform == 'win32':
294
add_pyrex_extension('bzrlib._dirstate_helpers_pyx',
295
libraries=['Ws2_32'])
296
add_pyrex_extension('bzrlib._walkdirs_win32')
298
if have_pyrex and pyrex_version_info[:3] == (0,9,4):
299
# Pyrex 0.9.4.1 fails to compile this extension correctly
300
# The code it generates re-uses a "local" pointer and
301
# calls "PY_DECREF" after having set it to NULL. (It mixes PY_XDECREF
302
# which is NULL safe with PY_DECREF which is not.)
303
# <https://bugs.launchpad.net/bzr/+bug/449372>
304
# <https://bugs.launchpad.net/bzr/+bug/276868>
305
print('Cannot build extension "bzrlib._dirstate_helpers_pyx" using')
306
print('your version of pyrex "%s". Please upgrade your pyrex'
308
print('install. For now, the non-compiled (python) version will')
309
print('be used instead.')
311
add_pyrex_extension('bzrlib._dirstate_helpers_pyx')
312
add_pyrex_extension('bzrlib._readdir_pyx')
313
add_pyrex_extension('bzrlib._chk_map_pyx')
314
ext_modules.append(Extension('bzrlib._patiencediff_c',
315
['bzrlib/_patiencediff_c.c']))
316
if have_pyrex and pyrex_version_info < (0, 9, 6, 3):
318
print('Your Pyrex/Cython version %s is too old to build the simple_set' % (
320
print('and static_tuple extensions.')
321
print('Please upgrade to at least Pyrex 0.9.6.3')
323
# TODO: Should this be a fatal error?
325
# We only need 0.9.6.3 to build _simple_set_pyx, but static_tuple depends
327
add_pyrex_extension('bzrlib._simple_set_pyx')
328
ext_modules.append(Extension('bzrlib._static_tuple_c',
329
['bzrlib/_static_tuple_c.c']))
330
add_pyrex_extension('bzrlib._btree_serializer_pyx')
333
if unavailable_files:
334
print('C extension(s) not found:')
335
print(' %s' % ('\n '.join(unavailable_files),))
336
print('The python versions will be used instead.')
340
def get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
341
gui_targets, data_files):
342
packages.append('tbzrcommands')
344
# ModuleFinder can't handle runtime changes to __path__, but
345
# win32com uses them. Hook this in so win32com.shell is found.
348
import cPickle as pickle
349
for p in win32com.__path__[1:]:
350
modulefinder.AddPackagePath("win32com", p)
351
for extra in ["win32com.shell"]:
353
m = sys.modules[extra]
354
for p in m.__path__[1:]:
355
modulefinder.AddPackagePath(extra, p)
357
# TBZR points to the TBZR directory
358
tbzr_root = os.environ["TBZR"]
360
# Ensure tbzrlib itself is on sys.path
361
sys.path.append(tbzr_root)
363
packages.append("tbzrlib")
365
# collect up our icons.
367
ico_root = os.path.join(tbzr_root, 'tbzrlib', 'resources')
368
icos = [] # list of (path_root, relative_ico_path)
369
# First always bzr's icon and its in the root of the bzr tree.
370
icos.append(('', 'bzr.ico'))
371
for root, dirs, files in os.walk(ico_root):
372
icos.extend([(ico_root, os.path.join(root, f)[len(ico_root)+1:])
373
for f in files if f.endswith('.ico')])
374
# allocate an icon ID for each file and the full path to the ico
375
icon_resources = [(rid, os.path.join(ico_dir, ico_name))
376
for rid, (ico_dir, ico_name) in enumerate(icos)]
377
# create a string resource with the mapping. Might as well save the
378
# runtime some effort and write a pickle.
379
# Runtime expects unicode objects with forward-slash seps.
380
fse = sys.getfilesystemencoding()
381
map_items = [(f.replace('\\', '/').decode(fse), rid)
382
for rid, (_, f) in enumerate(icos)]
383
ico_map = dict(map_items)
384
# Create a new resource type of 'ICON_MAP', and use ID=1
385
other_resources = [ ("ICON_MAP", 1, pickle.dumps(ico_map))]
387
excludes.extend("""pywin pywin.dialogs pywin.dialogs.list
388
win32ui crawler.Crawler""".split())
390
# tbzrcache executables - a "console" version for debugging and a
391
# GUI version that is generally used.
393
script = os.path.join(tbzr_root, "scripts", "tbzrcache.py"),
394
icon_resources = icon_resources,
395
other_resources = other_resources,
397
console_targets.append(tbzrcache)
399
# Make a windows version which is the same except for the base name.
400
tbzrcachew = tbzrcache.copy()
401
tbzrcachew["dest_base"]="tbzrcachew"
402
gui_targets.append(tbzrcachew)
404
# ditto for the tbzrcommand tool
406
script = os.path.join(tbzr_root, "scripts", "tbzrcommand.py"),
407
icon_resources = icon_resources,
408
other_resources = other_resources,
410
console_targets.append(tbzrcommand)
411
tbzrcommandw = tbzrcommand.copy()
412
tbzrcommandw["dest_base"]="tbzrcommandw"
413
gui_targets.append(tbzrcommandw)
415
# A utility to see python output from both C++ and Python based shell
417
tracer = dict(script=os.path.join(tbzr_root, "scripts", "tbzrtrace.py"))
418
console_targets.append(tracer)
420
# The C++ implemented shell extensions.
421
dist_dir = os.path.join(tbzr_root, "shellext", "build")
422
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x86.dll')]))
423
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x64.dll')]))
426
def get_qbzr_py2exe_info(includes, excludes, packages, data_files):
427
# PyQt4 itself still escapes the plugin detection code for some reason...
428
includes.append('PyQt4.QtCore')
429
includes.append('PyQt4.QtGui')
430
includes.append('sip') # extension module required for Qt.
431
packages.append('pygments') # colorizer for qbzr
432
packages.append('docutils') # html formatting
433
includes.append('win32event') # for qsubprocess stuff
434
# the qt binaries might not be on PATH...
435
# They seem to install to a place like C:\Python25\PyQt4\*
436
# Which is not the same as C:\Python25\Lib\site-packages\PyQt4
437
pyqt_dir = os.path.join(sys.prefix, "PyQt4")
438
pyqt_bin_dir = os.path.join(pyqt_dir, "bin")
439
if os.path.isdir(pyqt_bin_dir):
440
path = os.environ.get("PATH", "")
441
if pyqt_bin_dir.lower() not in [p.lower() for p in path.split(os.pathsep)]:
442
os.environ["PATH"] = path + os.pathsep + pyqt_bin_dir
443
# also add all imageformat plugins to distribution
444
# We will look in 2 places, dirname(PyQt4.__file__) and pyqt_dir
445
base_dirs_to_check = []
446
if os.path.isdir(pyqt_dir):
447
base_dirs_to_check.append(pyqt_dir)
453
pyqt4_base_dir = os.path.dirname(PyQt4.__file__)
454
if pyqt4_base_dir != pyqt_dir:
455
base_dirs_to_check.append(pyqt4_base_dir)
456
if not base_dirs_to_check:
457
log.warn("Can't find PyQt4 installation -> not including imageformat"
461
for base_dir in base_dirs_to_check:
462
plug_dir = os.path.join(base_dir, 'plugins', 'imageformats')
463
if os.path.isdir(plug_dir):
464
for fname in os.listdir(plug_dir):
465
# Include plugin dlls, but not debugging dlls
466
fullpath = os.path.join(plug_dir, fname)
467
if fname.endswith('.dll') and not fname.endswith('d4.dll'):
468
files.append(fullpath)
470
data_files.append(('imageformats', files))
472
log.warn('PyQt4 was found, but we could not find any imageformat'
473
' plugins. Are you sure your configuration is correct?')
476
def get_svn_py2exe_info(includes, excludes, packages):
477
packages.append('subvertpy')
478
packages.append('sqlite3')
481
if 'bdist_wininst' in sys.argv:
484
for root, dirs, files in os.walk('doc'):
487
if (os.path.splitext(f)[1] in ('.html','.css','.png','.pdf')
488
or f == 'quick-start-summary.svg'):
489
r.append(os.path.join(root, f))
493
target = os.path.join('Doc\\Bazaar', relative)
495
target = 'Doc\\Bazaar'
496
docs.append((target, r))
499
# python's distutils-based win32 installer
500
ARGS = {'scripts': ['bzr', 'tools/win32/bzr-win32-bdist-postinstall.py'],
501
'ext_modules': ext_modules,
503
'data_files': find_docs(),
504
# for building pyrex extensions
505
'cmdclass': command_classes,
508
ARGS.update(META_INFO)
510
ARGS.update(PKG_DATA)
514
elif 'py2exe' in sys.argv:
519
# pick real bzr version
523
for i in bzrlib.version_info[:4]:
528
version_number.append(str(i))
529
version_str = '.'.join(version_number)
531
# An override to install_data used only by py2exe builds, which arranges
532
# to byte-compile any .py files in data_files (eg, our plugins)
533
# Necessary as we can't rely on the user having the relevant permissions
534
# to the "Program Files" directory to generate them on the fly.
535
class install_data_with_bytecompile(install_data):
537
from distutils.util import byte_compile
539
install_data.run(self)
541
py2exe = self.distribution.get_command_obj('py2exe', False)
542
# GZ 2010-04-19: Setup has py2exe.optimize as 2, but give plugins
543
# time before living with docstring stripping
545
compile_names = [f for f in self.outfiles if f.endswith('.py')]
546
# Round mtime to nearest even second so that installing on a FAT
547
# filesystem bytecode internal and script timestamps will match
548
for f in compile_names:
549
mtime = os.stat(f).st_mtime
550
remainder = mtime % 2
553
os.utime(f, (mtime, mtime))
554
byte_compile(compile_names,
556
force=self.force, prefix=self.install_dir,
557
dry_run=self.dry_run)
558
self.outfiles.extend([f + 'o' for f in compile_names])
559
# end of class install_data_with_bytecompile
561
target = py2exe.build_exe.Target(script = "bzr",
563
icon_resources = [(0,'bzr.ico')],
564
name = META_INFO['name'],
565
version = version_str,
566
description = META_INFO['description'],
567
author = META_INFO['author'],
568
copyright = "(c) Canonical Ltd, 2005-2010",
569
company_name = "Canonical Ltd.",
570
comments = META_INFO['description'],
572
gui_target = copy.copy(target)
573
gui_target.dest_base = "bzrw"
575
packages = BZRLIB['packages']
576
packages.remove('bzrlib')
577
packages = [i for i in packages if not i.startswith('bzrlib.plugins')]
579
for i in glob.glob('bzrlib\\*.py'):
580
module = i[:-3].replace('\\', '.')
581
if module.endswith('__init__'):
582
module = module[:-len('__init__')]
583
includes.append(module)
585
additional_packages = set()
586
if sys.version.startswith('2.4'):
587
# adding elementtree package
588
additional_packages.add('elementtree')
589
elif sys.version.startswith('2.6') or sys.version.startswith('2.5'):
590
additional_packages.add('xml.etree')
593
warnings.warn('Unknown Python version.\n'
594
'Please check setup.py script for compatibility.')
596
# Although we currently can't enforce it, we consider it an error for
597
# py2exe to report any files are "missing". Such modules we know aren't
598
# used should be listed here.
599
excludes = """Tkinter psyco ElementPath r_hmac
600
ImaginaryModule cElementTree elementtree.ElementTree
601
Crypto.PublicKey._fastmath
602
medusa medusa.filesys medusa.ftp_server
604
resource validate""".split()
607
# email package from std python library use lazy import,
608
# so we need to explicitly add all package
609
additional_packages.add('email')
610
# And it uses funky mappings to conver to 'Oldname' to 'newname'. As
611
# a result, packages like 'email.Parser' show as missing. Tell py2exe
614
for oldname in getattr(email, '_LOWERNAMES', []):
615
excludes.append("email." + oldname)
616
for oldname in getattr(email, '_MIMENAMES', []):
617
excludes.append("email.MIME" + oldname)
619
# text files for help topis
620
text_topics = glob.glob('bzrlib/help_topics/en/*.txt')
621
topics_files = [('lib/help_topics/en', text_topics)]
625
# XXX - should we consider having the concept of an 'official' build,
626
# which hard-codes the list of plugins, gets more upset if modules are
628
plugins = None # will be a set after plugin sniffing...
629
for root, dirs, files in os.walk('bzrlib/plugins'):
630
if root == 'bzrlib/plugins':
632
# We ship plugins as normal files on the file-system - however,
633
# the build process can cause *some* of these plugin files to end
634
# up in library.zip. Thus, we saw (eg) "plugins/svn/test" in
635
# library.zip, and then saw import errors related to that as the
636
# rest of the svn plugin wasn't. So we tell py2exe to leave the
637
# plugins out of the .zip file
638
excludes.extend(["bzrlib.plugins." + d for d in dirs])
641
# Throw away files we don't want packaged. Note that plugins may
642
# have data files with all sorts of extensions so we need to
643
# be conservative here about what we ditch.
644
ext = os.path.splitext(i)[1]
645
if ext.endswith('~') or ext in [".pyc", ".swp"]:
647
if i == '__init__.py' and root == 'bzrlib/plugins':
649
x.append(os.path.join(root, i))
651
target_dir = root[len('bzrlib/'):] # install to 'plugins/...'
652
plugins_files.append((target_dir, x))
653
# find modules for built-in plugins
654
import tools.package_mf
655
mf = tools.package_mf.CustomModuleFinder()
656
mf.run_package('bzrlib/plugins')
657
packs, mods = mf.get_result()
658
additional_packages.update(packs)
659
includes.extend(mods)
661
console_targets = [target,
662
'tools/win32/bzr_postinstall.py',
664
gui_targets = [gui_target]
665
data_files = topics_files + plugins_files
667
if 'qbzr' in plugins:
668
get_qbzr_py2exe_info(includes, excludes, packages, data_files)
671
get_svn_py2exe_info(includes, excludes, packages)
673
if "TBZR" in os.environ:
674
# TORTOISE_OVERLAYS_MSI_WIN32 must be set to the location of the
675
# TortoiseOverlays MSI installer file. It is in the TSVN svn repo and
676
# can be downloaded from (username=guest, blank password):
677
# http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays
678
# look for: version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi
679
# Ditto for TORTOISE_OVERLAYS_MSI_X64, pointing at *-x64.msi.
680
for needed in ('TORTOISE_OVERLAYS_MSI_WIN32',
681
'TORTOISE_OVERLAYS_MSI_X64'):
682
url = ('http://guest:@tortoisesvn.tigris.org/svn/tortoisesvn'
684
if not os.path.isfile(os.environ.get(needed, '<nofile>')):
686
"\nPlease set %s to the location of the relevant"
687
"\nTortoiseOverlays .msi installer file."
688
" The installers can be found at"
690
"\ncheck in the version-X.Y.Z/bin/ subdir" % (needed, url))
691
get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
692
gui_targets, data_files)
694
# print this warning to stderr as output is redirected, so it is seen
695
# at build time. Also to stdout so it appears in the log
696
for f in (sys.stderr, sys.stdout):
697
f.write("Skipping TBZR binaries - "
698
"please set TBZR to a directory to enable\n")
700
# MSWSOCK.dll is a system-specific library, which py2exe accidentally pulls
702
dll_excludes.extend(["MSWSOCK.dll",
707
options_list = {"py2exe": {"packages": packages + list(additional_packages),
708
"includes": includes,
709
"excludes": excludes,
710
"dll_excludes": dll_excludes,
711
"dist_dir": "win32_bzr.exe",
713
"custom_boot_script":
714
"tools/win32/py2exe_boot_common.py",
718
# We want the libaray.zip to have optimize = 2, but the exe to have
719
# optimize = 1, so that .py files that get compilied at run time
720
# (e.g. user installed plugins) dont have their doc strings removed.
721
class py2exe_no_oo_exe(py2exe.build_exe.py2exe):
722
def build_executable(self, *args, **kwargs):
724
py2exe.build_exe.py2exe.build_executable(self, *args, **kwargs)
727
if __name__ == '__main__':
728
command_classes['install_data'] = install_data_with_bytecompile
729
command_classes['py2exe'] = py2exe_no_oo_exe
730
setup(options=options_list,
731
console=console_targets,
733
zipfile='lib/library.zip',
734
data_files=data_files,
735
cmdclass=command_classes,
739
# ad-hoc for easy_install
741
if not 'bdist_egg' in sys.argv:
742
# generate and install bzr.1 only with plain install, not the
744
DATA_FILES = [('man/man1', ['bzr.1'])]
747
ARGS = {'scripts': ['bzr'],
748
'data_files': DATA_FILES,
749
'cmdclass': command_classes,
750
'ext_modules': ext_modules,
753
ARGS.update(META_INFO)
755
ARGS.update(PKG_DATA)
757
if __name__ == '__main__':