15
if sys.version_info < (3, 5):
16
sys.stderr.write("[ERROR] Not a supported Python version. Need 3.5+\n")
23
sys.stderr.write("[ERROR] Please install setuptools\n")
15
if sys.version_info < (2, 6):
16
sys.stderr.write("[ERROR] Not a supported Python version. Need 2.6+\n")
27
19
# NOTE: The directory containing setup.py, whether run by 'python setup.py' or
28
20
# './setup.py' or the equivalent with another path, should always be at the
29
21
# start of the path, so this should find the right one...
32
24
def get_long_description():
33
25
dirname = os.path.dirname(__file__)
34
readme = os.path.join(dirname, 'README.rst')
35
with open(readme, 'r') as f:
26
readme = os.path.join(dirname, 'README')
27
f = open(readme, 'rb')
40
35
# META INFORMATION FOR SETUP
41
36
# see http://docs.python.org/dist/meta-data.html
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',
39
'version': brzlib.__version__,
40
'author': 'Canonical Ltd',
41
'author_email': 'bazaar@lists.canonical.com',
42
'url': 'http://bazaar.canonical.com/',
43
'description': 'Friendly distributed version control system',
44
'license': 'GNU GPL v2',
50
45
'download_url': 'https://launchpad.net/brz/+download',
51
46
'long_description': get_long_description(),
62
57
'Programming Language :: C',
63
58
'Topic :: Software Development :: Version Control',
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.
76
'launchpad': ['launchpadlib>=1.6.3'],
83
62
# The list of packages is automatically generated later. Add other things
84
# that are part of BREEZY here.
63
# that are part of BZRLIB here.
88
# install files from selftest suite
89
'package_data': {'breezy': ['doc/api/*.txt',
90
'tests/test_patches_data/*',
91
'help_topics/en/*.txt',
92
'tests/ssl_certs/ca.crt',
93
'tests/ssl_certs/server_without_pass.key',
94
'tests/ssl_certs/server_with_pass.key',
95
'tests/ssl_certs/server.crt',
66
PKG_DATA = {# install files from selftest suite
67
'package_data': {'brzlib': ['doc/api/*.txt',
68
'tests/test_patches_data/*',
69
'help_topics/en/*.txt',
70
'tests/ssl_certs/ca.crt',
71
'tests/ssl_certs/server_without_pass.key',
72
'tests/ssl_certs/server_with_pass.key',
73
'tests/ssl_certs/server.crt',
99
for filepath in glob.glob("breezy/locale/*/LC_MESSAGES/*.mo"):
100
langfile = filepath[len("breezy/locale/"):]
77
for filepath in glob.glob("brzlib/locale/*/LC_MESSAGES/*.mo"):
78
langfile = filepath[len("brzlib/locale/"):]
101
79
targetpath = os.path.dirname(os.path.join("share/locale", langfile))
102
80
I18N_FILES.append((targetpath, [filepath]))
104
def get_breezy_packages():
105
"""Recurse through the breezy directory, and extract the package names"""
82
def get_brzlib_packages():
83
"""Recurse through the brzlib directory, and extract the package names"""
108
base_path = os.path.dirname(os.path.abspath(breezy.__file__))
86
base_path = os.path.dirname(os.path.abspath(brzlib.__file__))
109
87
for root, dirs, files in os.walk(base_path):
110
88
if '__init__.py' in files:
111
89
assert root.startswith(base_path)
112
# Get just the path below breezy
90
# Get just the path below brzlib
113
91
package_path = root[len(base_path):]
114
92
# Remove leading and trailing slashes
115
93
package_path = package_path.strip('\\/')
116
94
if not package_path:
117
package_name = 'breezy'
95
package_name = 'brzlib'
121
package_path.replace('/', '.').replace('\\', '.'))
97
package_name = ('brzlib.' +
98
package_path.replace('/', '.').replace('\\', '.'))
122
99
packages.append(package_name)
123
100
return sorted(packages)
126
BREEZY['packages'] = get_breezy_packages()
129
from setuptools import setup
103
BZRLIB['packages'] = get_brzlib_packages()
106
from distutils import log
107
from distutils.core import setup
130
108
from distutils.version import LooseVersion
131
109
from distutils.command.install_scripts import install_scripts
132
110
from distutils.command.install_data import install_data
149
127
script_path = self._quoted_path(os.path.join(scripts_dir,
151
129
python_exe = self._quoted_path(sys.executable)
152
batch_str = "@%s %s %%*" % (python_exe, script_path)
130
args = self._win_batch_args()
131
batch_str = "@%s %s %s" % (python_exe, script_path, args)
153
132
batch_path = os.path.join(self.install_dir, "brz.bat")
154
with open(batch_path, "w") as f:
156
print(("Created: %s" % batch_path))
133
f = file(batch_path, "w")
136
print("Created: %s" % batch_path)
157
137
except Exception:
158
138
e = sys.exc_info()[1]
159
print(("ERROR: Unable to create %s: %s" % (batch_path, e)))
139
print("ERROR: Unable to create %s: %s" % (batch_path, e))
161
141
def _quoted_path(self, path):
163
143
return '"' + path + '"'
147
def _win_batch_args(self):
148
from brzlib.win32utils import winver
149
if winver == 'Windows NT':
152
return '%1 %2 %3 %4 %5 %6 %7 %8 %9'
166
153
#/class my_install_scripts
197
184
from distutils.extension import Extension
200
from Cython.Distutils import build_ext
201
from Cython.Compiler.Version import version as cython_version
188
from Cython.Distutils import build_ext
189
from Cython.Compiler.Version import version as pyrex_version
191
print("No Cython, trying Pyrex...")
192
from Pyrex.Distutils import build_ext
193
from Pyrex.Compiler.Version import version as pyrex_version
202
194
except ImportError:
204
196
# try to build the extension from the prior generated source.
206
print("The python package 'Cython' is not available."
198
print("The python package 'Pyrex' is not available."
207
199
" If the .c files are available,")
208
200
print("they will be built,"
209
201
" but modifying the .pyx files will not rebuild them.")
211
203
from distutils.command.build_ext import build_ext
213
minimum_cython_version = '0.29'
214
cython_version_info = LooseVersion(cython_version)
215
if cython_version_info < LooseVersion(minimum_cython_version):
216
print("Version of Cython is too old. "
217
"Current is %s, need at least %s."
218
% (cython_version, minimum_cython_version))
219
print("If the .c files are available, they will be built,"
220
" but modifying the .pyx files will not rebuild them.")
206
pyrex_version_info = LooseVersion(pyrex_version)
226
209
class build_ext_if_possible(build_ext):
267
# Override the build_ext if we have Cython available
250
# Override the build_ext if we have Pyrex available
268
251
command_classes['build_ext'] = build_ext_if_possible
269
252
unavailable_files = []
272
def add_cython_extension(module_name, libraries=None, extra_source=[]):
273
"""Add a cython module to build.
255
def add_pyrex_extension(module_name, libraries=None, extra_source=[]):
256
"""Add a pyrex module to build.
275
This will use Cython to auto-generate the .c file if it is available.
258
This will use Pyrex to auto-generate the .c file if it is available.
276
259
Otherwise it will fall back on the .c file. If the .c file is not
277
260
available, it will warn, and not add anything.
283
266
determine the .pyx and .c files to use.
285
268
path = module_name.replace('.', '/')
286
cython_name = path + '.pyx'
269
pyrex_name = path + '.pyx'
287
270
c_name = path + '.c'
288
271
define_macros = []
289
272
if sys.platform == 'win32':
290
# cython uses the macro WIN32 to detect the platform, even though it
273
# pyrex uses the macro WIN32 to detect the platform, even though it
291
274
# should be using something like _WIN32 or MS_WINDOWS, oh well, we can
292
275
# give it the right value.
293
276
define_macros.append(('WIN32', None))
295
source = [cython_name]
278
source = [pyrex_name]
297
280
if not os.path.isfile(c_name):
298
281
unavailable_files.append(c_name)
301
284
source = [c_name]
302
285
source.extend(extra_source)
303
include_dirs = ['breezy']
306
module_name, source, define_macros=define_macros,
307
libraries=libraries, include_dirs=include_dirs))
310
add_cython_extension('breezy._simple_set_pyx')
311
ext_modules.append(Extension('breezy._static_tuple_c',
312
['breezy/_static_tuple_c.c']))
313
add_cython_extension('breezy._annotator_pyx')
314
add_cython_extension('breezy._bencode_pyx')
315
add_cython_extension('breezy._chunks_to_lines_pyx')
316
add_cython_extension('breezy.bzr._groupcompress_pyx',
317
extra_source=['breezy/bzr/diff-delta.c'])
318
add_cython_extension('breezy.bzr._knit_load_data_pyx')
319
add_cython_extension('breezy._known_graph_pyx')
320
add_cython_extension('breezy._rio_pyx')
286
ext_modules.append(Extension(module_name, source,
287
define_macros=define_macros, libraries=libraries))
290
add_pyrex_extension('brzlib._annotator_pyx')
291
add_pyrex_extension('brzlib._bencode_pyx')
292
add_pyrex_extension('brzlib._chunks_to_lines_pyx')
293
add_pyrex_extension('brzlib._groupcompress_pyx',
294
extra_source=['brzlib/diff-delta.c'])
295
add_pyrex_extension('brzlib._knit_load_data_pyx')
296
add_pyrex_extension('brzlib._known_graph_pyx')
297
add_pyrex_extension('brzlib._rio_pyx')
321
298
if sys.platform == 'win32':
322
add_cython_extension('breezy.bzr._dirstate_helpers_pyx',
323
libraries=['Ws2_32'])
324
add_cython_extension('breezy._walkdirs_win32')
326
add_cython_extension('breezy.bzr._dirstate_helpers_pyx')
327
add_cython_extension('breezy._readdir_pyx')
328
add_cython_extension('breezy.bzr._chk_map_pyx')
329
add_cython_extension('breezy.bzr._btree_serializer_pyx')
299
add_pyrex_extension('brzlib._dirstate_helpers_pyx',
300
libraries=['Ws2_32'])
301
add_pyrex_extension('brzlib._walkdirs_win32')
303
if have_pyrex and pyrex_version_info == LooseVersion("0.9.4.1"):
304
# Pyrex 0.9.4.1 fails to compile this extension correctly
305
# The code it generates re-uses a "local" pointer and
306
# calls "PY_DECREF" after having set it to NULL. (It mixes PY_XDECREF
307
# which is NULL safe with PY_DECREF which is not.)
308
# <https://bugs.launchpad.net/brz/+bug/449372>
309
# <https://bugs.launchpad.net/brz/+bug/276868>
310
print('Cannot build extension "brzlib._dirstate_helpers_pyx" using')
311
print('your version of pyrex "%s". Please upgrade your pyrex'
313
print('install. For now, the non-compiled (python) version will')
314
print('be used instead.')
316
add_pyrex_extension('brzlib._dirstate_helpers_pyx')
317
add_pyrex_extension('brzlib._readdir_pyx')
318
add_pyrex_extension('brzlib._chk_map_pyx')
319
ext_modules.append(Extension('brzlib._patiencediff_c',
320
['brzlib/_patiencediff_c.c']))
321
if have_pyrex and pyrex_version_info < LooseVersion("0.9.6.3"):
323
print('Your Pyrex/Cython version %s is too old to build the simple_set' % (
325
print('and static_tuple extensions.')
326
print('Please upgrade to at least Pyrex 0.9.6.3')
328
# TODO: Should this be a fatal error?
330
# We only need 0.9.6.3 to build _simple_set_pyx, but static_tuple depends
332
add_pyrex_extension('brzlib._simple_set_pyx')
333
ext_modules.append(Extension('brzlib._static_tuple_c',
334
['brzlib/_static_tuple_c.c']))
335
add_pyrex_extension('brzlib._btree_serializer_pyx')
332
338
if unavailable_files:
333
339
print('C extension(s) not found:')
334
print((' %s' % ('\n '.join(unavailable_files),)))
340
print(' %s' % ('\n '.join(unavailable_files),))
335
341
print('The python versions will be used instead.')
356
362
# TBZR points to the TBZR directory
357
363
tbzr_root = os.environ["TBZR"]
359
# Ensure tbreezy itself is on sys.path
365
# Ensure tbrzlib itself is on sys.path
360
366
sys.path.append(tbzr_root)
362
packages.append("tbreezy")
368
packages.append("tbrzlib")
364
370
# collect up our icons.
365
371
cwd = os.getcwd()
366
ico_root = os.path.join(tbzr_root, 'tbreezy', 'resources')
372
ico_root = os.path.join(tbzr_root, 'tbrzlib', 'resources')
367
373
icos = [] # list of (path_root, relative_ico_path)
368
374
# First always brz's icon and its in the root of the brz tree.
369
375
icos.append(('', 'brz.ico'))
370
376
for root, dirs, files in os.walk(ico_root):
371
icos.extend([(ico_root, os.path.join(root, f)[len(ico_root) + 1:])
377
icos.extend([(ico_root, os.path.join(root, f)[len(ico_root)+1:])
372
378
for f in files if f.endswith('.ico')])
373
379
# allocate an icon ID for each file and the full path to the ico
374
380
icon_resources = [(rid, os.path.join(ico_dir, ico_name))
389
395
# tbzrcache executables - a "console" version for debugging and a
390
396
# GUI version that is generally used.
391
397
tbzrcache = dict(
392
script=os.path.join(tbzr_root, "scripts", "tbzrcache.py"),
393
icon_resources=icon_resources,
394
other_resources=other_resources,
398
script = os.path.join(tbzr_root, "scripts", "tbzrcache.py"),
399
icon_resources = icon_resources,
400
other_resources = other_resources,
396
402
console_targets.append(tbzrcache)
398
404
# Make a windows version which is the same except for the base name.
399
405
tbzrcachew = tbzrcache.copy()
400
tbzrcachew["dest_base"] = "tbzrcachew"
406
tbzrcachew["dest_base"]="tbzrcachew"
401
407
gui_targets.append(tbzrcachew)
403
409
# ditto for the tbzrcommand tool
404
410
tbzrcommand = dict(
405
script=os.path.join(tbzr_root, "scripts", "tbzrcommand.py"),
406
icon_resources=icon_resources,
407
other_resources=other_resources,
411
script = os.path.join(tbzr_root, "scripts", "tbzrcommand.py"),
412
icon_resources = icon_resources,
413
other_resources = other_resources,
409
415
console_targets.append(tbzrcommand)
410
416
tbzrcommandw = tbzrcommand.copy()
411
tbzrcommandw["dest_base"] = "tbzrcommandw"
417
tbzrcommandw["dest_base"]="tbzrcommandw"
412
418
gui_targets.append(tbzrcommandw)
414
420
# A utility to see python output from both C++ and Python based shell
416
422
tracer = dict(script=os.path.join(tbzr_root, "scripts", "tbzrtrace.py"))
494
500
for root, dirs, files in os.walk('doc'):
497
if (os.path.splitext(f)[1] in ('.html', '.css', '.png', '.pdf')
498
or f == 'quick-start-summary.svg'):
503
if (os.path.splitext(f)[1] in ('.html','.css','.png','.pdf')
504
or f == 'quick-start-summary.svg'):
499
505
r.append(os.path.join(root, f))
501
507
relative = root[4:]
503
target = os.path.join('Doc\\Breezy', relative)
509
target = os.path.join('Doc\\Bazaar', relative)
505
target = 'Doc\\Breezy'
511
target = 'Doc\\Bazaar'
506
512
docs.append((target, r))
568
574
self.outfiles.extend([f + 'o' for f in compile_names])
569
575
# end of class install_data_with_bytecompile
571
target = py2exe.build_exe.Target(
574
icon_resources=[(0, 'brz.ico')],
575
name=META_INFO['name'],
577
description=META_INFO['description'],
578
author=META_INFO['author'],
579
copyright="(c) Canonical Ltd, 2005-2010",
580
company_name="Canonical Ltd.",
581
comments=META_INFO['description'],
577
target = py2exe.build_exe.Target(script = "brz",
579
icon_resources = [(0,'brz.ico')],
580
name = META_INFO['name'],
581
version = version_str,
582
description = META_INFO['description'],
583
author = META_INFO['author'],
584
copyright = "(c) Canonical Ltd, 2005-2010",
585
company_name = "Canonical Ltd.",
586
comments = META_INFO['description'],
583
588
gui_target = copy.copy(target)
584
589
gui_target.dest_base = "bzrw"
586
packages = BREEZY['packages']
587
packages.remove('breezy')
588
packages = [i for i in packages if not i.startswith('breezy.plugins')]
591
packages = BZRLIB['packages']
592
packages.remove('brzlib')
593
packages = [i for i in packages if not i.startswith('brzlib.plugins')]
590
for i in glob.glob('breezy\\*.py'):
595
for i in glob.glob('brzlib\\*.py'):
591
596
module = i[:-3].replace('\\', '.')
592
597
if module.endswith('__init__'):
593
598
module = module[:-len('__init__')]
594
599
includes.append(module)
596
601
additional_packages = set()
602
if sys.version.startswith('2.4'):
603
# adding elementtree package
604
additional_packages.add('elementtree')
605
elif sys.version.startswith('2.6') or sys.version.startswith('2.5'):
606
additional_packages.add('xml.etree')
609
warnings.warn('Unknown Python version.\n'
610
'Please check setup.py script for compatibility.')
598
612
# Although we currently can't enforce it, we consider it an error for
599
613
# py2exe to report any files are "missing". Such modules we know aren't
645
660
ext = os.path.splitext(i)[1]
646
661
if ext.endswith('~') or ext in [".pyc", ".swp"]:
648
if i == '__init__.py' and root == 'breezy/plugins':
663
if i == '__init__.py' and root == 'brzlib/plugins':
650
665
x.append(os.path.join(root, i))
652
target_dir = root[len('breezy/'):] # install to 'plugins/...'
667
target_dir = root[len('brzlib/'):] # install to 'plugins/...'
653
668
plugins_files.append((target_dir, x))
654
669
# find modules for built-in plugins
655
670
import tools.package_mf
656
671
mf = tools.package_mf.CustomModuleFinder()
657
mf.run_package('breezy/plugins')
672
mf.run_package('brzlib/plugins')
658
673
packs, mods = mf.get_result()
659
674
additional_packages.update(packs)
660
675
includes.extend(mods)
746
761
# ad-hoc for easy_install
748
if 'bdist_egg' not in sys.argv:
763
if not 'bdist_egg' in sys.argv:
749
764
# generate and install brz.1 only with plain install, not the
750
765
# easy_install one
751
DATA_FILES = [('man/man1', ['brz.1', 'breezy/git/git-remote-bzr.1'])]
766
DATA_FILES = [('man/man1', ['brz.1'])]
753
768
DATA_FILES = DATA_FILES + I18N_FILES
755
ARGS = {'scripts': ['brz',
756
# TODO(jelmer): Only install the git scripts if
758
'breezy/git/git-remote-bzr',
759
'breezy/git/bzr-receive-pack',
760
'breezy/git/bzr-upload-pack'],
770
ARGS = {'scripts': ['brz'],
761
771
'data_files': DATA_FILES,
762
772
'cmdclass': command_classes,
763
773
'ext_modules': ext_modules,
766
776
ARGS.update(META_INFO)
768
778
ARGS.update(PKG_DATA)
770
780
if __name__ == '__main__':