setup.py
758 lines
| 28.3 KiB
| text/x-python
|
PythonLexer
mpm@selenic.com
|
r575 | # | ||
# This is the mercurial setup script. | ||||
mpm@selenic.com
|
r0 | # | ||
Christian Ebert
|
r4816 | # 'python setup.py install', or | ||
# 'python setup.py --help' for more options | ||||
mpm@selenic.com
|
r0 | |||
Zachary Gramana
|
r14295 | import sys, platform | ||
Pierre-Yves David
|
r25009 | if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'): | ||
raise SystemExit("Mercurial requires Python 2.6 or later.") | ||||
Thomas Arendsen Hein
|
r1873 | |||
Renato Cunha
|
r11532 | if sys.version_info[0] >= 3: | ||
Augie Fackler
|
r20696 | printf = eval('print') | ||
libdir_escape = 'unicode_escape' | ||||
Renato Cunha
|
r11532 | else: | ||
Augie Fackler
|
r20696 | libdir_escape = 'string_escape' | ||
def printf(*args, **kwargs): | ||||
f = kwargs.get('file', sys.stdout) | ||||
end = kwargs.get('end', '\n') | ||||
Gregory Szorc
|
r27348 | f.write(b' '.join(args) + end) | ||
Renato Cunha
|
r11532 | |||
Matt Mackall
|
r7558 | # Solaris Python packaging brain damage | ||
try: | ||||
import hashlib | ||||
sha = hashlib.sha1() | ||||
Brodie Rao
|
r16688 | except ImportError: | ||
Matt Mackall
|
r7558 | try: | ||
import sha | ||||
Mads Kiilerich
|
r22198 | sha.sha # silence unused import warning | ||
Brodie Rao
|
r16688 | except ImportError: | ||
Matt Mackall
|
r7558 | raise SystemExit( | ||
"Couldn't import standard hashlib (incomplete Python install).") | ||||
try: | ||||
import zlib | ||||
Mads Kiilerich
|
r22198 | zlib.compressobj # silence unused import warning | ||
Brodie Rao
|
r16688 | except ImportError: | ||
Matt Mackall
|
r7558 | raise SystemExit( | ||
"Couldn't import standard zlib (incomplete Python install).") | ||||
Zachary Gramana
|
r14295 | # The base IronPython distribution (as of 2.7.1) doesn't support bz2 | ||
isironpython = False | ||||
Dirkjan Ochtman
|
r10761 | try: | ||
Brodie Rao
|
r16683 | isironpython = (platform.python_implementation() | ||
.lower().find("ironpython") != -1) | ||||
Brodie Rao
|
r16688 | except AttributeError: | ||
Zachary Gramana
|
r14295 | pass | ||
if isironpython: | ||||
Simon Heimberg
|
r15492 | sys.stderr.write("warning: IronPython detected (no bz2 support)\n") | ||
Zachary Gramana
|
r14295 | else: | ||
try: | ||||
import bz2 | ||||
Mads Kiilerich
|
r22198 | bz2.BZ2Compressor # silence unused import warning | ||
Brodie Rao
|
r16688 | except ImportError: | ||
Zachary Gramana
|
r14295 | raise SystemExit( | ||
"Couldn't import standard bz2 (incomplete Python install).") | ||||
Dirkjan Ochtman
|
r10761 | |||
Joan Massich
|
r24192 | ispypy = "PyPy" in sys.version | ||
Gregory Szorc
|
r29020 | import ctypes | ||
Kyle Lippincott
|
r22640 | import os, stat, subprocess, time | ||
Kent Frazier
|
r21038 | import re | ||
Alexis S. L. Carvalho
|
r6251 | import shutil | ||
import tempfile | ||||
Christian Boos
|
r11468 | from distutils import log | ||
Nathan Goldbaum
|
r26600 | if 'FORCE_SETUPTOOLS' in os.environ: | ||
from setuptools import setup | ||||
else: | ||||
from distutils.core import setup | ||||
Jun Wu
|
r30408 | from distutils.ccompiler import new_compiler | ||
Nathan Goldbaum
|
r26600 | from distutils.core import Command, Extension | ||
Martin Geisler
|
r7722 | from distutils.dist import Distribution | ||
Martin Geisler
|
r7649 | from distutils.command.build import build | ||
Christian Boos
|
r11468 | from distutils.command.build_ext import build_ext | ||
Martin Geisler
|
r7722 | from distutils.command.build_py import build_py | ||
Gregory Szorc
|
r27268 | from distutils.command.build_scripts import build_scripts | ||
Kyle Lippincott
|
r22640 | from distutils.command.install_lib import install_lib | ||
Dan Villiom Podlaski Christiansen
|
r12661 | from distutils.command.install_scripts import install_scripts | ||
Martin Geisler
|
r7649 | from distutils.spawn import spawn, find_executable | ||
Ludovic Chabant
|
r23677 | from distutils import file_util | ||
Gregory Szorc
|
r27268 | from distutils.errors import ( | ||
CCompilerError, | ||||
DistutilsError, | ||||
DistutilsExecError, | ||||
) | ||||
Kent Frazier
|
r21038 | from distutils.sysconfig import get_python_inc, get_config_var | ||
Dirkjan Ochtman
|
r13594 | from distutils.version import StrictVersion | ||
mpm@selenic.com
|
r157 | |||
Paul Moore
|
r6513 | scripts = ['hg'] | ||
if os.name == 'nt': | ||||
Gregory Szorc
|
r27268 | # We remove hg.bat if we are able to build hg.exe. | ||
Paul Moore
|
r6513 | scripts.append('contrib/win32/hg.bat') | ||
Matt Mackall
|
r3893 | |||
Alexis S. L. Carvalho
|
r6251 | # simplified version of distutils.ccompiler.CCompiler.has_function | ||
# that actually removes its temporary files. | ||||
Martin Geisler
|
r10000 | def hasfunction(cc, funcname): | ||
Alexis S. L. Carvalho
|
r6251 | tmpdir = tempfile.mkdtemp(prefix='hg-install-') | ||
Alexis S. L. Carvalho
|
r6373 | devnull = oldstderr = None | ||
Alexis S. L. Carvalho
|
r6251 | try: | ||
Matt Mackall
|
r25089 | fname = os.path.join(tmpdir, 'funcname.c') | ||
f = open(fname, 'w') | ||||
f.write('int main(void) {\n') | ||||
f.write(' %s();\n' % funcname) | ||||
f.write('}\n') | ||||
f.close() | ||||
# Redirect stderr to /dev/null to hide any error messages | ||||
# from the compiler. | ||||
# This will have to be changed if we ever have to check | ||||
# for a function on Windows. | ||||
devnull = open('/dev/null', 'w') | ||||
oldstderr = os.dup(sys.stderr.fileno()) | ||||
os.dup2(devnull.fileno(), sys.stderr.fileno()) | ||||
objects = cc.compile([fname], output_dir=tmpdir) | ||||
cc.link_executable(objects, os.path.join(tmpdir, "a.out")) | ||||
Alexis S. L. Carvalho
|
r6251 | return True | ||
Matt Mackall
|
r25089 | except Exception: | ||
return False | ||||
Alexis S. L. Carvalho
|
r6251 | finally: | ||
Alexis S. L. Carvalho
|
r6373 | if oldstderr is not None: | ||
os.dup2(oldstderr, sys.stderr.fileno()) | ||||
if devnull is not None: | ||||
devnull.close() | ||||
Alexis S. L. Carvalho
|
r6251 | shutil.rmtree(tmpdir) | ||
Volker.Kleinfeld@gmx.de
|
r1283 | # py2exe needs to be installed to work | ||
try: | ||||
Bryan O'Sullivan
|
r1294 | import py2exe | ||
Mads Kiilerich
|
r22198 | py2exe.Distribution # silence unused import warning | ||
Adrian Buehlmann
|
r10400 | py2exeloaded = True | ||
Pascal Quantin
|
r15527 | # import py2exe's patched Distribution class | ||
from distutils.core import Distribution | ||||
Bryan O'Sullivan
|
r1284 | except ImportError: | ||
Adrian Buehlmann
|
r10400 | py2exeloaded = False | ||
Volker.Kleinfeld@gmx.de
|
r1283 | |||
Christian Boos
|
r9807 | def runcmd(cmd, env): | ||
Jeff Sickel
|
r23392 | if (sys.platform == 'plan9' | ||
and (sys.version_info[0] == 2 and sys.version_info[1] < 7)): | ||||
Steven Stallion
|
r16383 | # subprocess kludge to work around issues in half-baked Python | ||
# ports, notably bichued/python: | ||||
_, out, err = os.popen3(cmd) | ||||
return str(out), str(err) | ||||
else: | ||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, | ||||
stderr=subprocess.PIPE, env=env) | ||||
out, err = p.communicate() | ||||
return out, err | ||||
Jon M. Dugan
|
r13636 | |||
def runhg(cmd, env): | ||||
out, err = runcmd(cmd, env) | ||||
Gilles Moris
|
r9615 | # If root is executing setup.py, but the repository is owned by | ||
# another user (as in "sudo python setup.py install") we will get | ||||
# trust warnings since the .hg/hgrc file is untrusted. That is | ||||
Steve Borho
|
r10120 | # fine, we don't want to load it anyway. Python may warn about | ||
# a missing __init__.py in mercurial/locale, we also ignore that. | ||||
Gilles Moris
|
r9615 | err = [e for e in err.splitlines() | ||
Gregory Szorc
|
r27348 | if not e.startswith(b'not trusting file') \ | ||
and not e.startswith(b'warning: Not importing') \ | ||||
and not e.startswith(b'obsolete feature not enabled')] | ||||
Gilles Moris
|
r9615 | if err: | ||
Augie Fackler
|
r20696 | printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr) | ||
Gregory Szorc
|
r27348 | printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr) | ||
Gilles Moris
|
r9615 | return '' | ||
return out | ||||
version = '' | ||||
Jeremy Whitlock
|
r8548 | |||
Gregory Szorc
|
r27220 | # Execute hg out of this directory with a custom environment which takes care | ||
# to not use any hgrc files and do no localization. | ||||
env = {'HGMODULEPOLICY': 'py', | ||||
Yuya Nishihara
|
r15388 | 'HGRCPATH': '', | ||
Gábor Stefanik
|
r30458 | 'LANGUAGE': 'C', | ||
'PATH': ''} # make pypi modules that use os.environ['PATH'] happy | ||||
Yuya Nishihara
|
r15388 | if 'LD_LIBRARY_PATH' in os.environ: | ||
env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] | ||||
if 'SystemRoot' in os.environ: | ||||
# Copy SystemRoot into the custom environment for Python 2.6 | ||||
# under Windows. Otherwise, the subprocess will fail with | ||||
# error 0xc0150004. See: http://bugs.python.org/issue3440 | ||||
env['SystemRoot'] = os.environ['SystemRoot'] | ||||
Matt Mackall
|
r15367 | |||
Christian Ebert
|
r8547 | if os.path.isdir('.hg'): | ||
Bryan O'Sullivan
|
r17709 | cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n'] | ||
numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()] | ||||
hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip() | ||||
if numerictags: # tag(s) found | ||||
version = numerictags[-1] | ||||
if hgid.endswith('+'): # propagate the dirty status to the tag | ||||
Gilles Moris
|
r9615 | version += '+' | ||
Bryan O'Sullivan
|
r17709 | else: # no tag found | ||
Siddharth Agarwal
|
r23647 | ltagcmd = [sys.executable, 'hg', 'parents', '--template', | ||
'{latesttag}'] | ||||
ltag = runhg(ltagcmd, env) | ||||
changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r', | ||||
"only(.,'%s')" % ltag] | ||||
changessince = len(runhg(changessincecmd, env).splitlines()) | ||||
version = '%s+%s-%s' % (ltag, changessince, hgid) | ||||
Gilles Moris
|
r9615 | if version.endswith('+'): | ||
version += time.strftime('%Y%m%d') | ||||
elif os.path.exists('.hg_archival.txt'): | ||||
Martin Geisler
|
r10124 | kw = dict([[t.strip() for t in l.split(':', 1)] | ||
for l in open('.hg_archival.txt')]) | ||||
Gilles Moris
|
r9615 | if 'tag' in kw: | ||
timeless
|
r27637 | version = kw['tag'] | ||
Gilles Moris
|
r9615 | elif 'latesttag' in kw: | ||
Siddharth Agarwal
|
r23646 | if 'changessincelatesttag' in kw: | ||
version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw | ||||
else: | ||||
version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw | ||||
Christian Ebert
|
r8547 | else: | ||
Gilles Moris
|
r9615 | version = kw.get('node', '')[:12] | ||
Matt Mackall
|
r7632 | |||
Jeremy Whitlock
|
r8548 | if version: | ||
timeless
|
r28418 | with open("mercurial/__version__.py", "w") as f: | ||
f.write('# this file is autogenerated by setup.py\n') | ||||
f.write('version = "%s"\n' % version) | ||||
Jeremy Whitlock
|
r8493 | |||
try: | ||||
timeless
|
r28431 | oldpolicy = os.environ.get('HGMODULEPOLICY', None) | ||
os.environ['HGMODULEPOLICY'] = 'py' | ||||
Jeremy Whitlock
|
r8493 | from mercurial import __version__ | ||
version = __version__.version | ||||
except ImportError: | ||||
version = 'unknown' | ||||
timeless
|
r28431 | finally: | ||
if oldpolicy is None: | ||||
del os.environ['HGMODULEPOLICY'] | ||||
else: | ||||
os.environ['HGMODULEPOLICY'] = oldpolicy | ||||
Matt Mackall
|
r7632 | |||
Simon Heimberg
|
r15460 | class hgbuild(build): | ||
# Insert hgbuildmo first so that files in mercurial/locale/ are found | ||||
# when build_py is run next. | ||||
Gregory Szorc
|
r28398 | sub_commands = [('build_mo', None)] + build.sub_commands | ||
Simon Heimberg
|
r15460 | |||
Matt Mackall
|
r15523 | class hgbuildmo(build): | ||
Martin Geisler
|
r7649 | |||
description = "build translations (.mo files)" | ||||
def run(self): | ||||
if not find_executable('msgfmt'): | ||||
self.warn("could not find msgfmt executable, no translations " | ||||
"will be built") | ||||
return | ||||
podir = 'i18n' | ||||
if not os.path.isdir(podir): | ||||
self.warn("could not find %s/ directory" % podir) | ||||
return | ||||
join = os.path.join | ||||
for po in os.listdir(podir): | ||||
if not po.endswith('.po'): | ||||
continue | ||||
pofile = join(podir, po) | ||||
modir = join('locale', po[:-3], 'LC_MESSAGES') | ||||
mofile = join(modir, 'hg.mo') | ||||
Dan Villiom Podlaski Christiansen
|
r9999 | mobuildfile = join('mercurial', mofile) | ||
cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile] | ||||
Martin Geisler
|
r7720 | if sys.platform != 'sunos5': | ||
# msgfmt on Solaris does not know about -c | ||||
cmd.append('-c') | ||||
Dan Villiom Podlaski Christiansen
|
r9999 | self.mkpath(join('mercurial', modir)) | ||
self.make_file([pofile], mobuildfile, spawn, (cmd,)) | ||||
Martin Geisler
|
r7649 | |||
Dan Villiom Podlaski Christiansen
|
r12661 | |||
Simon Heimberg
|
r15458 | class hgdist(Distribution): | ||
Maciej Fijalkowski
|
r29505 | pure = False | ||
cffi = ispypy | ||||
Simon Heimberg
|
r15458 | |||
global_options = Distribution.global_options + \ | ||||
[('pure', None, "use pure (slow) Python " | ||||
"code instead of C extensions"), | ||||
] | ||||
Martin Geisler
|
r7722 | |||
Simon Heimberg
|
r15459 | def has_ext_modules(self): | ||
# self.ext_modules is emptied in hgbuildpy.finalize_options which is | ||||
# too late for some cases | ||||
return not self.pure and Distribution.has_ext_modules(self) | ||||
Gregory Szorc
|
r30450 | # This is ugly as a one-liner. So use a variable. | ||
buildextnegops = dict(getattr(build_ext, 'negative_options', {})) | ||||
buildextnegops['no-zstd'] = 'zstd' | ||||
Christian Boos
|
r11468 | class hgbuildext(build_ext): | ||
Gregory Szorc
|
r30450 | user_options = build_ext.user_options + [ | ||
('zstd', None, 'compile zstd bindings [default]'), | ||||
('no-zstd', None, 'do not compile zstd bindings'), | ||||
] | ||||
boolean_options = build_ext.boolean_options + ['zstd'] | ||||
negative_opt = buildextnegops | ||||
def initialize_options(self): | ||||
self.zstd = True | ||||
return build_ext.initialize_options(self) | ||||
def build_extensions(self): | ||||
# Filter out zstd if disabled via argument. | ||||
if not self.zstd: | ||||
self.extensions = [e for e in self.extensions | ||||
if e.name != 'mercurial.zstd'] | ||||
return build_ext.build_extensions(self) | ||||
Christian Boos
|
r11468 | |||
def build_extension(self, ext): | ||||
try: | ||||
build_ext.build_extension(self, ext) | ||||
except CCompilerError: | ||||
Martin Geisler
|
r12501 | if not getattr(ext, 'optional', False): | ||
Christian Boos
|
r11468 | raise | ||
log.warn("Failed to build optional extension '%s' (skipping)", | ||||
ext.name) | ||||
Gregory Szorc
|
r27268 | class hgbuildscripts(build_scripts): | ||
def run(self): | ||||
FUJIWARA Katsunori
|
r28041 | if os.name != 'nt' or self.distribution.pure: | ||
Gregory Szorc
|
r27268 | return build_scripts.run(self) | ||
exebuilt = False | ||||
try: | ||||
self.run_command('build_hgexe') | ||||
exebuilt = True | ||||
except (DistutilsError, CCompilerError): | ||||
log.warn('failed to build optional hg.exe') | ||||
if exebuilt: | ||||
# Copying hg.exe to the scripts build directory ensures it is | ||||
# installed by the install_scripts command. | ||||
hgexecommand = self.get_finalized_command('build_hgexe') | ||||
dest = os.path.join(self.build_dir, 'hg.exe') | ||||
self.mkpath(self.build_dir) | ||||
self.copy_file(hgexecommand.hgexepath, dest) | ||||
# Remove hg.bat because it is redundant with hg.exe. | ||||
self.scripts.remove('contrib/win32/hg.bat') | ||||
return build_scripts.run(self) | ||||
Martin Geisler
|
r10000 | class hgbuildpy(build_py): | ||
Martin Geisler
|
r7722 | def finalize_options(self): | ||
build_py.finalize_options(self) | ||||
if self.distribution.pure: | ||||
self.distribution.ext_modules = [] | ||||
Maciej Fijalkowski
|
r29505 | elif self.distribution.cffi: | ||
Jun Wu
|
r30346 | from mercurial.cffi import ( | ||
bdiff, | ||||
mpatch, | ||||
) | ||||
exts = [mpatch.ffi.distutils_extension(), | ||||
bdiff.ffi.distutils_extension()] | ||||
Maciej Fijalkowski
|
r29505 | # cffi modules go here | ||
Maciej Fijalkowski
|
r29600 | if sys.platform == 'darwin': | ||
Jun Wu
|
r30346 | from mercurial.cffi import osutil | ||
exts.append(osutil.ffi.distutils_extension()) | ||||
Maciej Fijalkowski
|
r29505 | self.distribution.ext_modules = exts | ||
Nicolas Dumazet
|
r12649 | else: | ||
Mads Kiilerich
|
r18905 | h = os.path.join(get_python_inc(), 'Python.h') | ||
if not os.path.exists(h): | ||||
Brodie Rao
|
r16683 | raise SystemExit('Python headers are required to build ' | ||
Mads Kiilerich
|
r18905 | 'Mercurial but weren\'t found in %s' % h) | ||
Martin Geisler
|
r7722 | |||
timeless
|
r28430 | def run(self): | ||
if self.distribution.pure: | ||||
modulepolicy = 'py' | ||||
else: | ||||
modulepolicy = 'c' | ||||
with open("mercurial/__modulepolicy__.py", "w") as f: | ||||
f.write('# this file is autogenerated by setup.py\n') | ||||
f.write('modulepolicy = "%s"\n' % modulepolicy) | ||||
Gregory Szorc
|
r27222 | |||
timeless
|
r28430 | build_py.run(self) | ||
Martin Geisler
|
r7722 | |||
Yuya Nishihara
|
r14538 | class buildhgextindex(Command): | ||
description = 'generate prebuilt index of hgext (for frozen package)' | ||||
user_options = [] | ||||
_indexfilename = 'hgext/__index__.py' | ||||
def initialize_options(self): | ||||
pass | ||||
def finalize_options(self): | ||||
pass | ||||
def run(self): | ||||
if os.path.exists(self._indexfilename): | ||||
timeless
|
r28418 | with open(self._indexfilename, 'w') as f: | ||
f.write('# empty\n') | ||||
Yuya Nishihara
|
r14538 | |||
# here no extension enabled, disabled() lists up everything | ||||
code = ('import pprint; from mercurial import extensions; ' | ||||
'pprint.pprint(extensions.disabled())') | ||||
out, err = runcmd([sys.executable, '-c', code], env) | ||||
if err: | ||||
raise DistutilsExecError(err) | ||||
timeless
|
r28418 | with open(self._indexfilename, 'w') as f: | ||
f.write('# this file is autogenerated by setup.py\n') | ||||
f.write('docs = ') | ||||
f.write(out) | ||||
Yuya Nishihara
|
r14538 | |||
Adrian Buehlmann
|
r17061 | class buildhgexe(build_ext): | ||
description = 'compile hg.exe from mercurial/exewrapper.c' | ||||
def build_extensions(self): | ||||
if os.name != 'nt': | ||||
return | ||||
Adrian Buehlmann
|
r17246 | if isinstance(self.compiler, HackedMingw32CCompiler): | ||
self.compiler.compiler_so = self.compiler.compiler # no -mdll | ||||
self.compiler.dll_libraries = [] # no -lmsrvc90 | ||||
Gregory Szorc
|
r29020 | |||
# Different Python installs can have different Python library | ||||
# names. e.g. the official CPython distribution uses pythonXY.dll | ||||
# and MinGW uses libpythonX.Y.dll. | ||||
_kernel32 = ctypes.windll.kernel32 | ||||
_kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p, | ||||
ctypes.c_void_p, | ||||
ctypes.c_ulong] | ||||
_kernel32.GetModuleFileNameA.restype = ctypes.c_ulong | ||||
size = 1000 | ||||
buf = ctypes.create_string_buffer(size + 1) | ||||
filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf), | ||||
size) | ||||
if filelen > 0 and filelen != size: | ||||
dllbasename = os.path.basename(buf.value) | ||||
if not dllbasename.lower().endswith('.dll'): | ||||
raise SystemExit('Python DLL does not end with .dll: %s' % | ||||
dllbasename) | ||||
pythonlib = dllbasename[:-4] | ||||
else: | ||||
log.warn('could not determine Python DLL filename; ' | ||||
'assuming pythonXY') | ||||
hv = sys.hexversion | ||||
pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff) | ||||
log.info('using %s as Python library name' % pythonlib) | ||||
timeless
|
r28418 | with open('mercurial/hgpythonlib.h', 'wb') as f: | ||
f.write('/* this file is autogenerated by setup.py */\n') | ||||
f.write('#define HGPYTHONLIB "%s"\n' % pythonlib) | ||||
Adrian Buehlmann
|
r17061 | objects = self.compiler.compile(['mercurial/exewrapper.c'], | ||
output_dir=self.build_temp) | ||||
dir = os.path.dirname(self.get_ext_fullpath('dummy')) | ||||
target = os.path.join(dir, 'hg') | ||||
self.compiler.link_executable(objects, target, | ||||
Adrian Buehlmann
|
r17732 | libraries=[], | ||
Adrian Buehlmann
|
r17061 | output_dir=self.build_temp) | ||
Gregory Szorc
|
r27268 | @property | ||
def hgexepath(self): | ||||
dir = os.path.dirname(self.get_ext_fullpath('dummy')) | ||||
return os.path.join(self.build_temp, dir, 'hg.exe') | ||||
Kyle Lippincott
|
r22640 | class hginstalllib(install_lib): | ||
''' | ||||
This is a specialization of install_lib that replaces the copy_file used | ||||
there so that it supports setting the mode of files after copying them, | ||||
instead of just preserving the mode that the files originally had. If your | ||||
system has a umask of something like 027, preserving the permissions when | ||||
copying will lead to a broken install. | ||||
Note that just passing keep_permissions=False to copy_file would be | ||||
insufficient, as it might still be applying a umask. | ||||
''' | ||||
def run(self): | ||||
realcopyfile = file_util.copy_file | ||||
def copyfileandsetmode(*args, **kwargs): | ||||
src, dst = args[0], args[1] | ||||
dst, copied = realcopyfile(*args, **kwargs) | ||||
if copied: | ||||
st = os.stat(src) | ||||
# Persist executable bit (apply it to group and other if user | ||||
# has it) | ||||
if st[stat.ST_MODE] & stat.S_IXUSR: | ||||
Augie Fackler
|
r24941 | setmode = int('0755', 8) | ||
Kyle Lippincott
|
r22640 | else: | ||
Augie Fackler
|
r24941 | setmode = int('0644', 8) | ||
m = stat.S_IMODE(st[stat.ST_MODE]) | ||||
m = (m & ~int('0777', 8)) | setmode | ||||
os.chmod(dst, m) | ||||
Kyle Lippincott
|
r22640 | file_util.copy_file = copyfileandsetmode | ||
try: | ||||
install_lib.run(self) | ||||
finally: | ||||
file_util.copy_file = realcopyfile | ||||
Dan Villiom Podlaski Christiansen
|
r12661 | class hginstallscripts(install_scripts): | ||
''' | ||||
This is a specialization of install_scripts that replaces the @LIBDIR@ with | ||||
the configured directory for modules. If possible, the path is made relative | ||||
to the directory for scripts. | ||||
''' | ||||
def initialize_options(self): | ||||
install_scripts.initialize_options(self) | ||||
self.install_lib = None | ||||
def finalize_options(self): | ||||
install_scripts.finalize_options(self) | ||||
self.set_undefined_options('install', | ||||
('install_lib', 'install_lib')) | ||||
def run(self): | ||||
install_scripts.run(self) | ||||
Gregory Szorc
|
r27269 | # It only makes sense to replace @LIBDIR@ with the install path if | ||
# the install path is known. For wheels, the logic below calculates | ||||
# the libdir to be "../..". This is because the internal layout of a | ||||
# wheel archive looks like: | ||||
# | ||||
# mercurial-3.6.1.data/scripts/hg | ||||
# mercurial/__init__.py | ||||
# | ||||
# When installing wheels, the subdirectories of the "<pkg>.data" | ||||
# directory are translated to system local paths and files therein | ||||
# are copied in place. The mercurial/* files are installed into the | ||||
# site-packages directory. However, the site-packages directory | ||||
# isn't known until wheel install time. This means we have no clue | ||||
# at wheel generation time what the installed site-packages directory | ||||
# will be. And, wheels don't appear to provide the ability to register | ||||
# custom code to run during wheel installation. This all means that | ||||
# we can't reliably set the libdir in wheels: the default behavior | ||||
# of looking in sys.path must do. | ||||
Dan Villiom Podlaski Christiansen
|
r12661 | if (os.path.splitdrive(self.install_dir)[0] != | ||
os.path.splitdrive(self.install_lib)[0]): | ||||
# can't make relative paths from one drive to another, so use an | ||||
# absolute path instead | ||||
libdir = self.install_lib | ||||
else: | ||||
common = os.path.commonprefix((self.install_dir, self.install_lib)) | ||||
rest = self.install_dir[len(common):] | ||||
uplevel = len([n for n in os.path.split(rest) if n]) | ||||
timeless
|
r27637 | libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):] | ||
Dan Villiom Podlaski Christiansen
|
r12661 | |||
for outfile in self.outfiles: | ||||
timeless
|
r28418 | with open(outfile, 'rb') as fp: | ||
data = fp.read() | ||||
Dan Villiom Podlaski Christiansen
|
r12661 | |||
# skip binary files | ||||
Gregory Szorc
|
r27348 | if b'\0' in data: | ||
Dan Villiom Podlaski Christiansen
|
r12661 | continue | ||
Gregory Szorc
|
r27269 | # During local installs, the shebang will be rewritten to the final | ||
# install path. During wheel packaging, the shebang has a special | ||||
# value. | ||||
if data.startswith(b'#!python'): | ||||
log.info('not rewriting @LIBDIR@ in %s because install path ' | ||||
'not known' % outfile) | ||||
continue | ||||
Gregory Szorc
|
r27348 | data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape)) | ||
timeless
|
r28418 | with open(outfile, 'wb') as fp: | ||
fp.write(data) | ||||
Dan Villiom Podlaski Christiansen
|
r12661 | |||
Simon Heimberg
|
r15460 | cmdclass = {'build': hgbuild, | ||
'build_mo': hgbuildmo, | ||||
Christian Boos
|
r11468 | 'build_ext': hgbuildext, | ||
Dan Villiom Podlaski Christiansen
|
r12661 | 'build_py': hgbuildpy, | ||
Gregory Szorc
|
r27268 | 'build_scripts': hgbuildscripts, | ||
Yuya Nishihara
|
r14538 | 'build_hgextindex': buildhgextindex, | ||
Kyle Lippincott
|
r22640 | 'install_lib': hginstalllib, | ||
Adrian Buehlmann
|
r17061 | 'install_scripts': hginstallscripts, | ||
'build_hgexe': buildhgexe, | ||||
} | ||||
Thomas Arendsen Hein
|
r3238 | |||
Augie Fackler
|
r16775 | packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient', | ||
Gregory Szorc
|
r27222 | 'mercurial.pure', | ||
Sean Farley
|
r28625 | 'hgext', 'hgext.convert', 'hgext.fsmonitor', | ||
'hgext.fsmonitor.pywatchman', 'hgext.highlight', | ||||
'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd'] | ||||
Benoit Boissinot
|
r10521 | |||
Maciej Fijalkowski
|
r29444 | common_depends = ['mercurial/bitmanipulation.h', | ||
'mercurial/compat.h', | ||||
'mercurial/util.h'] | ||||
Wei, Elson
|
r19724 | |||
Jun Wu
|
r30408 | osutil_cflags = [] | ||
Adrian Buehlmann
|
r25073 | osutil_ldflags = [] | ||
Jun Wu
|
r30408 | # platform specific macros: HAVE_SETPROCTITLE | ||
for plat, func in [(re.compile('freebsd'), 'setproctitle')]: | ||||
if plat.search(sys.platform) and hasfunction(new_compiler(), func): | ||||
osutil_cflags.append('-DHAVE_%s' % func.upper()) | ||||
Adrian Buehlmann
|
r25073 | if sys.platform == 'darwin': | ||
osutil_ldflags += ['-framework', 'ApplicationServices'] | ||||
Martin Geisler
|
r10000 | extmodules = [ | ||
Wei, Elson
|
r19724 | Extension('mercurial.base85', ['mercurial/base85.c'], | ||
depends=common_depends), | ||||
Maciej Fijalkowski
|
r29541 | Extension('mercurial.bdiff', ['mercurial/bdiff.c', | ||
'mercurial/bdiff_module.c'], | ||||
depends=common_depends + ['mercurial/bdiff.h']), | ||||
Wei, Elson
|
r19724 | Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'], | ||
depends=common_depends), | ||||
Maciej Fijalkowski
|
r29693 | Extension('mercurial.mpatch', ['mercurial/mpatch.c', | ||
'mercurial/mpatch_module.c'], | ||||
Wei, Elson
|
r19724 | depends=common_depends), | ||
Bryan O'Sullivan
|
r18900 | Extension('mercurial.parsers', ['mercurial/dirs.c', | ||
Augie Fackler
|
r24214 | 'mercurial/manifest.c', | ||
Bryan O'Sullivan
|
r18900 | 'mercurial/parsers.c', | ||
Wei, Elson
|
r19724 | 'mercurial/pathencode.c'], | ||
depends=common_depends), | ||||
Adrian Buehlmann
|
r25074 | Extension('mercurial.osutil', ['mercurial/osutil.c'], | ||
Jun Wu
|
r30408 | extra_compile_args=osutil_cflags, | ||
Adrian Buehlmann
|
r25074 | extra_link_args=osutil_ldflags, | ||
depends=common_depends), | ||||
Martijn Pieters
|
r28432 | Extension('hgext.fsmonitor.pywatchman.bser', | ||
['hgext/fsmonitor/pywatchman/bser.c']), | ||||
Bryan O'Sullivan
|
r5396 | ] | ||
Gregory Szorc
|
r30436 | sys.path.insert(0, 'contrib/python-zstandard') | ||
import setup_zstd | ||||
Gregory Szorc
|
r30698 | extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd')) | ||
Gregory Szorc
|
r30436 | |||
Ludovic Chabant
|
r23677 | try: | ||
from distutils import cygwinccompiler | ||||
# the -mno-cygwin option has been deprecated for years | ||||
compiler = cygwinccompiler.Mingw32CCompiler | ||||
Bryan O'Sullivan
|
r17121 | |||
Ludovic Chabant
|
r23677 | class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler): | ||
def __init__(self, *args, **kwargs): | ||||
compiler.__init__(self, *args, **kwargs) | ||||
for i in 'compiler compiler_so linker_exe linker_so'.split(): | ||||
try: | ||||
getattr(self, i).remove('-mno-cygwin') | ||||
except ValueError: | ||||
pass | ||||
Bryan O'Sullivan
|
r17121 | |||
Ludovic Chabant
|
r23677 | cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler | ||
except ImportError: | ||||
# the cygwinccompiler package is not available on some Python | ||||
# distributions like the ones from the optware project for Synology | ||||
# DiskStation boxes | ||||
class HackedMingw32CCompiler(object): | ||||
pass | ||||
Bryan O'Sullivan
|
r17121 | |||
Dan Villiom Podlaski Christiansen
|
r9999 | packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo', | ||
Mads Kiilerich
|
r22575 | 'help/*.txt', | ||
Gregory Szorc
|
r27374 | 'help/internals/*.txt', | ||
Mads Kiilerich
|
r23142 | 'default.d/*.rc', | ||
Mads Kiilerich
|
r22575 | 'dummycert.pem']} | ||
Dan Villiom Podlaski Christiansen
|
r9999 | |||
def ordinarypath(p): | ||||
return p and p[0] != '.' and p[-1] != '~' | ||||
Matt Mackall
|
r10282 | for root in ('templates',): | ||
Dan Villiom Podlaski Christiansen
|
r9999 | for curdir, dirs, files in os.walk(os.path.join('mercurial', root)): | ||
curdir = curdir.split(os.sep, 1)[1] | ||||
dirs[:] = filter(ordinarypath, dirs) | ||||
for f in filter(ordinarypath, files): | ||||
f = os.path.join(curdir, f) | ||||
packagedata['mercurial'].append(f) | ||||
Martin Geisler
|
r7648 | datafiles = [] | ||
Adrian Buehlmann
|
r10400 | setupversion = version | ||
extra = {} | ||||
if py2exeloaded: | ||||
extra['console'] = [ | ||||
{'script':'hg', | ||||
timeless
|
r27925 | 'copyright':'Copyright (C) 2005-2016 Matt Mackall and others', | ||
Adrian Buehlmann
|
r10400 | 'product_version':version}] | ||
Yuya Nishihara
|
r14538 | # sub command of 'build' because 'py2exe' does not handle sub_commands | ||
build.sub_commands.insert(0, ('build_hgextindex', None)) | ||||
Steve Borho
|
r25409 | # put dlls in sub directory so that they won't pollute PATH | ||
extra['zipfile'] = 'lib/library.zip' | ||||
Adrian Buehlmann
|
r10400 | |||
if os.name == 'nt': | ||||
# Windows binary file versions for exe/dll files must have the | ||||
# form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535 | ||||
setupversion = version.split('+', 1)[0] | ||||
Martin Geisler
|
r7648 | |||
Alexander Solovyov
|
r13583 | if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'): | ||
Greg Ward
|
r16187 | version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines() | ||
if version: | ||||
Brendan Cully
|
r16209 | version = version[0] | ||
Augie Fackler
|
r25043 | if sys.version_info[0] == 3: | ||
version = version.decode('utf-8') | ||||
Greg Ward
|
r16187 | xcode4 = (version.startswith('Xcode') and | ||
StrictVersion(version.split()[1]) >= StrictVersion('4.0')) | ||||
Matt Mackall
|
r21558 | xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None | ||
Greg Ward
|
r16187 | else: | ||
# xcodebuild returns empty on OS X Lion with XCode 4.3 not | ||||
# installed, but instead with only command-line tools. Assume | ||||
# that only happens on >= Lion, thus no PPC support. | ||||
xcode4 = True | ||||
Kent Frazier
|
r21038 | xcode51 = False | ||
Greg Ward
|
r16187 | |||
Kent Frazier
|
r21038 | # XCode 4.0 dropped support for ppc architecture, which is hardcoded in | ||
# distutils.sysconfig | ||||
Greg Ward
|
r16187 | if xcode4: | ||
Brendan Cully
|
r14324 | os.environ['ARCHFLAGS'] = '' | ||
Alexander Solovyov
|
r13583 | |||
Kent Frazier
|
r21038 | # XCode 5.1 changes clang such that it now fails to compile if the | ||
# -mno-fused-madd flag is passed, but the version of Python shipped with | ||||
# OS X 10.9 Mavericks includes this flag. This causes problems in all | ||||
# C extension modules, and a bug has been filed upstream at | ||||
# http://bugs.python.org/issue21244. We also need to patch this here | ||||
# so Mercurial can continue to compile in the meantime. | ||||
if xcode51: | ||||
cflags = get_config_var('CFLAGS') | ||||
Alex Gaynor
|
r21839 | if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None: | ||
Kent Frazier
|
r21038 | os.environ['CFLAGS'] = ( | ||
os.environ.get('CFLAGS', '') + ' -Qunused-arguments') | ||||
Thomas Arendsen Hein
|
r1977 | setup(name='mercurial', | ||
Adrian Buehlmann
|
r10400 | version=setupversion, | ||
Benoit Boissinot
|
r18753 | author='Matt Mackall and many others', | ||
author_email='mercurial@selenic.com', | ||||
Matt Mackall
|
r26421 | url='https://mercurial-scm.org/', | ||
download_url='https://mercurial-scm.org/release/', | ||||
Benoit Boissinot
|
r18753 | description=('Fast scalable distributed SCM (revision control, version ' | ||
'control) system'), | ||||
long_description=('Mercurial is a distributed SCM tool written in Python.' | ||||
' It is used by a number of large projects that require' | ||||
' fast, reliable distributed revision control, such as ' | ||||
'Mozilla.'), | ||||
license='GNU GPLv2 or any later version', | ||||
classifiers=[ | ||||
'Development Status :: 6 - Mature', | ||||
'Environment :: Console', | ||||
'Intended Audience :: Developers', | ||||
'Intended Audience :: System Administrators', | ||||
'License :: OSI Approved :: GNU General Public License (GPL)', | ||||
'Natural Language :: Danish', | ||||
'Natural Language :: English', | ||||
'Natural Language :: German', | ||||
'Natural Language :: Italian', | ||||
'Natural Language :: Japanese', | ||||
'Natural Language :: Portuguese (Brazilian)', | ||||
'Operating System :: Microsoft :: Windows', | ||||
'Operating System :: OS Independent', | ||||
'Operating System :: POSIX', | ||||
'Programming Language :: C', | ||||
'Programming Language :: Python', | ||||
'Topic :: Software Development :: Version Control', | ||||
], | ||||
Paul Moore
|
r6513 | scripts=scripts, | ||
Bryan O'Sullivan
|
r6239 | packages=packages, | ||
Martin Geisler
|
r10000 | ext_modules=extmodules, | ||
Martin Geisler
|
r7648 | data_files=datafiles, | ||
Dan Villiom Podlaski Christiansen
|
r9999 | package_data=packagedata, | ||
Thomas Arendsen Hein
|
r3238 | cmdclass=cmdclass, | ||
Simon Heimberg
|
r15458 | distclass=hgdist, | ||
Augie Fackler
|
r20687 | options={'py2exe': {'packages': ['hgext', 'email']}, | ||
Mads Kiilerich
|
r22358 | 'bdist_mpkg': {'zipdist': False, | ||
Augie Fackler
|
r20687 | 'license': 'COPYING', | ||
'readme': 'contrib/macosx/Readme.html', | ||||
'welcome': 'contrib/macosx/Welcome.html', | ||||
}, | ||||
}, | ||||
Matt Mackall
|
r3893 | **extra) | ||