##// END OF EJS Templates
setup: prefer using the system hg to interact with the local repository...
Adam Simpkins -
r33114:8b20338b default
parent child Browse files
Show More
@@ -1,850 +1,894 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if sys.version_info < (2, 7, 0, 'final'):
8 if sys.version_info < (2, 7, 0, 'final'):
9 raise SystemExit('Mercurial requires Python 2.7 or later.')
9 raise SystemExit('Mercurial requires Python 2.7 or later.')
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 printf = eval('print')
12 printf = eval('print')
13 libdir_escape = 'unicode_escape'
13 libdir_escape = 'unicode_escape'
14 else:
14 else:
15 libdir_escape = 'string_escape'
15 libdir_escape = 'string_escape'
16 def printf(*args, **kwargs):
16 def printf(*args, **kwargs):
17 f = kwargs.get('file', sys.stdout)
17 f = kwargs.get('file', sys.stdout)
18 end = kwargs.get('end', '\n')
18 end = kwargs.get('end', '\n')
19 f.write(b' '.join(args) + end)
19 f.write(b' '.join(args) + end)
20
20
21 # Solaris Python packaging brain damage
21 # Solaris Python packaging brain damage
22 try:
22 try:
23 import hashlib
23 import hashlib
24 sha = hashlib.sha1()
24 sha = hashlib.sha1()
25 except ImportError:
25 except ImportError:
26 try:
26 try:
27 import sha
27 import sha
28 sha.sha # silence unused import warning
28 sha.sha # silence unused import warning
29 except ImportError:
29 except ImportError:
30 raise SystemExit(
30 raise SystemExit(
31 "Couldn't import standard hashlib (incomplete Python install).")
31 "Couldn't import standard hashlib (incomplete Python install).")
32
32
33 try:
33 try:
34 import zlib
34 import zlib
35 zlib.compressobj # silence unused import warning
35 zlib.compressobj # silence unused import warning
36 except ImportError:
36 except ImportError:
37 raise SystemExit(
37 raise SystemExit(
38 "Couldn't import standard zlib (incomplete Python install).")
38 "Couldn't import standard zlib (incomplete Python install).")
39
39
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
41 isironpython = False
41 isironpython = False
42 try:
42 try:
43 isironpython = (platform.python_implementation()
43 isironpython = (platform.python_implementation()
44 .lower().find("ironpython") != -1)
44 .lower().find("ironpython") != -1)
45 except AttributeError:
45 except AttributeError:
46 pass
46 pass
47
47
48 if isironpython:
48 if isironpython:
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
50 else:
50 else:
51 try:
51 try:
52 import bz2
52 import bz2
53 bz2.BZ2Compressor # silence unused import warning
53 bz2.BZ2Compressor # silence unused import warning
54 except ImportError:
54 except ImportError:
55 raise SystemExit(
55 raise SystemExit(
56 "Couldn't import standard bz2 (incomplete Python install).")
56 "Couldn't import standard bz2 (incomplete Python install).")
57
57
58 ispypy = "PyPy" in sys.version
58 ispypy = "PyPy" in sys.version
59
59
60 import ctypes
60 import ctypes
61 import os, stat, subprocess, time
61 import os, stat, subprocess, time
62 import re
62 import re
63 import shutil
63 import shutil
64 import tempfile
64 import tempfile
65 from distutils import log
65 from distutils import log
66 # We have issues with setuptools on some platforms and builders. Until
66 # We have issues with setuptools on some platforms and builders. Until
67 # those are resolved, setuptools is opt-in except for platforms where
67 # those are resolved, setuptools is opt-in except for platforms where
68 # we don't have issues.
68 # we don't have issues.
69 if os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ:
69 if os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ:
70 from setuptools import setup
70 from setuptools import setup
71 else:
71 else:
72 from distutils.core import setup
72 from distutils.core import setup
73 from distutils.ccompiler import new_compiler
73 from distutils.ccompiler import new_compiler
74 from distutils.core import Command, Extension
74 from distutils.core import Command, Extension
75 from distutils.dist import Distribution
75 from distutils.dist import Distribution
76 from distutils.command.build import build
76 from distutils.command.build import build
77 from distutils.command.build_ext import build_ext
77 from distutils.command.build_ext import build_ext
78 from distutils.command.build_py import build_py
78 from distutils.command.build_py import build_py
79 from distutils.command.build_scripts import build_scripts
79 from distutils.command.build_scripts import build_scripts
80 from distutils.command.install import install
80 from distutils.command.install import install
81 from distutils.command.install_lib import install_lib
81 from distutils.command.install_lib import install_lib
82 from distutils.command.install_scripts import install_scripts
82 from distutils.command.install_scripts import install_scripts
83 from distutils.spawn import spawn, find_executable
83 from distutils.spawn import spawn, find_executable
84 from distutils import file_util
84 from distutils import file_util
85 from distutils.errors import (
85 from distutils.errors import (
86 CCompilerError,
86 CCompilerError,
87 DistutilsError,
87 DistutilsError,
88 DistutilsExecError,
88 DistutilsExecError,
89 )
89 )
90 from distutils.sysconfig import get_python_inc, get_config_var
90 from distutils.sysconfig import get_python_inc, get_config_var
91 from distutils.version import StrictVersion
91 from distutils.version import StrictVersion
92
92
93 scripts = ['hg']
93 scripts = ['hg']
94 if os.name == 'nt':
94 if os.name == 'nt':
95 # We remove hg.bat if we are able to build hg.exe.
95 # We remove hg.bat if we are able to build hg.exe.
96 scripts.append('contrib/win32/hg.bat')
96 scripts.append('contrib/win32/hg.bat')
97
97
98 def cancompile(cc, code):
98 def cancompile(cc, code):
99 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
99 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
100 devnull = oldstderr = None
100 devnull = oldstderr = None
101 try:
101 try:
102 fname = os.path.join(tmpdir, 'testcomp.c')
102 fname = os.path.join(tmpdir, 'testcomp.c')
103 f = open(fname, 'w')
103 f = open(fname, 'w')
104 f.write(code)
104 f.write(code)
105 f.close()
105 f.close()
106 # Redirect stderr to /dev/null to hide any error messages
106 # Redirect stderr to /dev/null to hide any error messages
107 # from the compiler.
107 # from the compiler.
108 # This will have to be changed if we ever have to check
108 # This will have to be changed if we ever have to check
109 # for a function on Windows.
109 # for a function on Windows.
110 devnull = open('/dev/null', 'w')
110 devnull = open('/dev/null', 'w')
111 oldstderr = os.dup(sys.stderr.fileno())
111 oldstderr = os.dup(sys.stderr.fileno())
112 os.dup2(devnull.fileno(), sys.stderr.fileno())
112 os.dup2(devnull.fileno(), sys.stderr.fileno())
113 objects = cc.compile([fname], output_dir=tmpdir)
113 objects = cc.compile([fname], output_dir=tmpdir)
114 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
114 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
115 return True
115 return True
116 except Exception:
116 except Exception:
117 return False
117 return False
118 finally:
118 finally:
119 if oldstderr is not None:
119 if oldstderr is not None:
120 os.dup2(oldstderr, sys.stderr.fileno())
120 os.dup2(oldstderr, sys.stderr.fileno())
121 if devnull is not None:
121 if devnull is not None:
122 devnull.close()
122 devnull.close()
123 shutil.rmtree(tmpdir)
123 shutil.rmtree(tmpdir)
124
124
125 # simplified version of distutils.ccompiler.CCompiler.has_function
125 # simplified version of distutils.ccompiler.CCompiler.has_function
126 # that actually removes its temporary files.
126 # that actually removes its temporary files.
127 def hasfunction(cc, funcname):
127 def hasfunction(cc, funcname):
128 code = 'int main(void) { %s(); }\n' % funcname
128 code = 'int main(void) { %s(); }\n' % funcname
129 return cancompile(cc, code)
129 return cancompile(cc, code)
130
130
131 def hasheader(cc, headername):
131 def hasheader(cc, headername):
132 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
132 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
133 return cancompile(cc, code)
133 return cancompile(cc, code)
134
134
135 # py2exe needs to be installed to work
135 # py2exe needs to be installed to work
136 try:
136 try:
137 import py2exe
137 import py2exe
138 py2exe.Distribution # silence unused import warning
138 py2exe.Distribution # silence unused import warning
139 py2exeloaded = True
139 py2exeloaded = True
140 # import py2exe's patched Distribution class
140 # import py2exe's patched Distribution class
141 from distutils.core import Distribution
141 from distutils.core import Distribution
142 except ImportError:
142 except ImportError:
143 py2exeloaded = False
143 py2exeloaded = False
144
144
145 def runcmd(cmd, env):
145 def runcmd(cmd, env):
146 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
146 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
147 stderr=subprocess.PIPE, env=env)
147 stderr=subprocess.PIPE, env=env)
148 out, err = p.communicate()
148 out, err = p.communicate()
149 return p.returncode, out, err
149 return p.returncode, out, err
150
150
151 class hgcommand(object):
151 class hgcommand(object):
152 def __init__(self):
152 def __init__(self, cmd, env):
153 self.cmd = [sys.executable, 'hg']
153 self.cmd = cmd
154 self.env = gethgenv()
154 self.env = env
155
155
156 def run(self, args):
156 def run(self, args):
157 cmd = self.cmd + args
157 cmd = self.cmd + args
158 returncode, out, err = runcmd(cmd, self.env)
158 returncode, out, err = runcmd(cmd, self.env)
159 # If root is executing setup.py, but the repository is owned by
159 # If root is executing setup.py, but the repository is owned by
160 # another user (as in "sudo python setup.py install") we will get
160 # another user (as in "sudo python setup.py install") we will get
161 # trust warnings since the .hg/hgrc file is untrusted. That is
161 # trust warnings since the .hg/hgrc file is untrusted. That is
162 # fine, we don't want to load it anyway. Python may warn about
162 # fine, we don't want to load it anyway. Python may warn about
163 # a missing __init__.py in mercurial/locale, we also ignore that.
163 # a missing __init__.py in mercurial/locale, we also ignore that.
164 err = [e for e in err.splitlines()
164 err = [e for e in err.splitlines()
165 if not e.startswith(b'not trusting file') \
165 if not e.startswith(b'not trusting file') \
166 and not e.startswith(b'warning: Not importing') \
166 and not e.startswith(b'warning: Not importing') \
167 and not e.startswith(b'obsolete feature not enabled')]
167 and not e.startswith(b'obsolete feature not enabled')]
168 if err or returncode != 0:
168 if err or returncode != 0:
169 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
169 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
170 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
170 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
171 return ''
171 return ''
172 return out
172 return out
173
173
174 def gethgenv():
174 def findhg():
175 """Try to figure out how we should invoke hg for examining the local
176 repository contents.
177
178 Returns an hgcommand object."""
179 # By default, prefer the "hg" command in the user's path. This was
180 # presumably the hg command that the user used to create this repository.
181 #
182 # This repository may require extensions or other settings that would not
183 # be enabled by running the hg script directly from this local repository.
184 hgenv = os.environ.copy()
185 # Use HGPLAIN to disable hgrc settings that would change output formatting,
186 # and disable localization for the same reasons.
187 hgenv['HGPLAIN'] = '1'
188 hgenv['LANGUAGE'] = 'C'
189 hgcmd = ['hg']
190 # Run a simple "hg log" command just to see if using hg from the user's
191 # path works and can successfully interact with this repository.
192 check_cmd = ['log', '-r.', '-Ttest']
193 try:
194 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
195 except EnvironmentError:
196 retcode = -1
197 if retcode == 0:
198 return hgcommand(hgcmd, hgenv)
199
200 # Fall back to trying the local hg installation.
201 hgenv = localhgenv()
202 # Don't source any system hgrc files when using the local hg.
203 hgenv['HGRCPATH'] = ''
204 hgcmd = [sys.executable, 'hg']
205 try:
206 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
207 except EnvironmentError:
208 retcode = -1
209 if retcode == 0:
210 return hgcommand(hgcmd, hgenv)
211
212 raise SystemExit('Unable to find a working hg binary to extract the '
213 'version from the repository tags')
214
215 def localhgenv():
216 """Get an environment dictionary to use for invoking or importing
217 mercurial from the local repository."""
175 # Execute hg out of this directory with a custom environment which takes
218 # Execute hg out of this directory with a custom environment which takes
176 # care to not use any hgrc files and do no localization.
219 # care to not use any hgrc files and do no localization.
177 env = {'HGMODULEPOLICY': 'py',
220 env = {'HGMODULEPOLICY': 'py',
178 'HGRCPATH': '',
221 'HGRCPATH': '',
179 'LANGUAGE': 'C',
222 'LANGUAGE': 'C',
180 'PATH': ''} # make pypi modules that use os.environ['PATH'] happy
223 'PATH': ''} # make pypi modules that use os.environ['PATH'] happy
181 if 'LD_LIBRARY_PATH' in os.environ:
224 if 'LD_LIBRARY_PATH' in os.environ:
182 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
225 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
183 if 'SystemRoot' in os.environ:
226 if 'SystemRoot' in os.environ:
184 # SystemRoot is required by Windows to load various DLLs. See:
227 # SystemRoot is required by Windows to load various DLLs. See:
185 # https://bugs.python.org/issue13524#msg148850
228 # https://bugs.python.org/issue13524#msg148850
186 env['SystemRoot'] = os.environ['SystemRoot']
229 env['SystemRoot'] = os.environ['SystemRoot']
187
230
188 version = ''
231 version = ''
189
232
190 if os.path.isdir('.hg'):
233 if os.path.isdir('.hg'):
191 hg = hgcommand()
234 hg = findhg()
192 cmd = ['log', '-r', '.', '--template', '{tags}\n']
235 cmd = ['log', '-r', '.', '--template', '{tags}\n']
193 numerictags = [t for t in hg.run(cmd).split() if t[0:1].isdigit()]
236 numerictags = [t for t in hg.run(cmd).split() if t[0:1].isdigit()]
194 hgid = hg.run(['id', '-i']).strip()
237 hgid = hg.run(['id', '-i']).strip()
195 if not hgid:
238 if not hgid:
196 # Bail out if hg is having problems interacting with this repository,
239 # Bail out if hg is having problems interacting with this repository,
197 # rather than falling through and producing a bogus version number.
240 # rather than falling through and producing a bogus version number.
198 # Continuing with an invalid version number will break extensions
241 # Continuing with an invalid version number will break extensions
199 # that define minimumhgversion.
242 # that define minimumhgversion.
200 raise SystemExit('Unable to determine hg version from local repository')
243 raise SystemExit('Unable to determine hg version from local repository')
201 if numerictags: # tag(s) found
244 if numerictags: # tag(s) found
202 version = numerictags[-1]
245 version = numerictags[-1]
203 if hgid.endswith('+'): # propagate the dirty status to the tag
246 if hgid.endswith('+'): # propagate the dirty status to the tag
204 version += '+'
247 version += '+'
205 else: # no tag found
248 else: # no tag found
206 ltagcmd = ['parents', '--template', '{latesttag}']
249 ltagcmd = ['parents', '--template', '{latesttag}']
207 ltag = hg.run(ltagcmd)
250 ltag = hg.run(ltagcmd)
208 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
251 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
209 changessince = len(hg.run(changessincecmd).splitlines())
252 changessince = len(hg.run(changessincecmd).splitlines())
210 version = '%s+%s-%s' % (ltag, changessince, hgid)
253 version = '%s+%s-%s' % (ltag, changessince, hgid)
211 if version.endswith('+'):
254 if version.endswith('+'):
212 version += time.strftime('%Y%m%d')
255 version += time.strftime('%Y%m%d')
213 elif os.path.exists('.hg_archival.txt'):
256 elif os.path.exists('.hg_archival.txt'):
214 kw = dict([[t.strip() for t in l.split(':', 1)]
257 kw = dict([[t.strip() for t in l.split(':', 1)]
215 for l in open('.hg_archival.txt')])
258 for l in open('.hg_archival.txt')])
216 if 'tag' in kw:
259 if 'tag' in kw:
217 version = kw['tag']
260 version = kw['tag']
218 elif 'latesttag' in kw:
261 elif 'latesttag' in kw:
219 if 'changessincelatesttag' in kw:
262 if 'changessincelatesttag' in kw:
220 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
263 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
221 else:
264 else:
222 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
265 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
223 else:
266 else:
224 version = kw.get('node', '')[:12]
267 version = kw.get('node', '')[:12]
225
268
226 if version:
269 if version:
227 with open("mercurial/__version__.py", "w") as f:
270 with open("mercurial/__version__.py", "w") as f:
228 f.write('# this file is autogenerated by setup.py\n')
271 f.write('# this file is autogenerated by setup.py\n')
229 f.write('version = "%s"\n' % version)
272 f.write('version = "%s"\n' % version)
230
273
231 try:
274 try:
232 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
275 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
233 os.environ['HGMODULEPOLICY'] = 'py'
276 os.environ['HGMODULEPOLICY'] = 'py'
234 from mercurial import __version__
277 from mercurial import __version__
235 version = __version__.version
278 version = __version__.version
236 except ImportError:
279 except ImportError:
237 version = 'unknown'
280 version = 'unknown'
238 finally:
281 finally:
239 if oldpolicy is None:
282 if oldpolicy is None:
240 del os.environ['HGMODULEPOLICY']
283 del os.environ['HGMODULEPOLICY']
241 else:
284 else:
242 os.environ['HGMODULEPOLICY'] = oldpolicy
285 os.environ['HGMODULEPOLICY'] = oldpolicy
243
286
244 class hgbuild(build):
287 class hgbuild(build):
245 # Insert hgbuildmo first so that files in mercurial/locale/ are found
288 # Insert hgbuildmo first so that files in mercurial/locale/ are found
246 # when build_py is run next.
289 # when build_py is run next.
247 sub_commands = [('build_mo', None)] + build.sub_commands
290 sub_commands = [('build_mo', None)] + build.sub_commands
248
291
249 class hgbuildmo(build):
292 class hgbuildmo(build):
250
293
251 description = "build translations (.mo files)"
294 description = "build translations (.mo files)"
252
295
253 def run(self):
296 def run(self):
254 if not find_executable('msgfmt'):
297 if not find_executable('msgfmt'):
255 self.warn("could not find msgfmt executable, no translations "
298 self.warn("could not find msgfmt executable, no translations "
256 "will be built")
299 "will be built")
257 return
300 return
258
301
259 podir = 'i18n'
302 podir = 'i18n'
260 if not os.path.isdir(podir):
303 if not os.path.isdir(podir):
261 self.warn("could not find %s/ directory" % podir)
304 self.warn("could not find %s/ directory" % podir)
262 return
305 return
263
306
264 join = os.path.join
307 join = os.path.join
265 for po in os.listdir(podir):
308 for po in os.listdir(podir):
266 if not po.endswith('.po'):
309 if not po.endswith('.po'):
267 continue
310 continue
268 pofile = join(podir, po)
311 pofile = join(podir, po)
269 modir = join('locale', po[:-3], 'LC_MESSAGES')
312 modir = join('locale', po[:-3], 'LC_MESSAGES')
270 mofile = join(modir, 'hg.mo')
313 mofile = join(modir, 'hg.mo')
271 mobuildfile = join('mercurial', mofile)
314 mobuildfile = join('mercurial', mofile)
272 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
315 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
273 if sys.platform != 'sunos5':
316 if sys.platform != 'sunos5':
274 # msgfmt on Solaris does not know about -c
317 # msgfmt on Solaris does not know about -c
275 cmd.append('-c')
318 cmd.append('-c')
276 self.mkpath(join('mercurial', modir))
319 self.mkpath(join('mercurial', modir))
277 self.make_file([pofile], mobuildfile, spawn, (cmd,))
320 self.make_file([pofile], mobuildfile, spawn, (cmd,))
278
321
279
322
280 class hgdist(Distribution):
323 class hgdist(Distribution):
281 pure = False
324 pure = False
282 cffi = ispypy
325 cffi = ispypy
283
326
284 global_options = Distribution.global_options + \
327 global_options = Distribution.global_options + \
285 [('pure', None, "use pure (slow) Python "
328 [('pure', None, "use pure (slow) Python "
286 "code instead of C extensions"),
329 "code instead of C extensions"),
287 ]
330 ]
288
331
289 def has_ext_modules(self):
332 def has_ext_modules(self):
290 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
333 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
291 # too late for some cases
334 # too late for some cases
292 return not self.pure and Distribution.has_ext_modules(self)
335 return not self.pure and Distribution.has_ext_modules(self)
293
336
294 # This is ugly as a one-liner. So use a variable.
337 # This is ugly as a one-liner. So use a variable.
295 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
338 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
296 buildextnegops['no-zstd'] = 'zstd'
339 buildextnegops['no-zstd'] = 'zstd'
297
340
298 class hgbuildext(build_ext):
341 class hgbuildext(build_ext):
299 user_options = build_ext.user_options + [
342 user_options = build_ext.user_options + [
300 ('zstd', None, 'compile zstd bindings [default]'),
343 ('zstd', None, 'compile zstd bindings [default]'),
301 ('no-zstd', None, 'do not compile zstd bindings'),
344 ('no-zstd', None, 'do not compile zstd bindings'),
302 ]
345 ]
303
346
304 boolean_options = build_ext.boolean_options + ['zstd']
347 boolean_options = build_ext.boolean_options + ['zstd']
305 negative_opt = buildextnegops
348 negative_opt = buildextnegops
306
349
307 def initialize_options(self):
350 def initialize_options(self):
308 self.zstd = True
351 self.zstd = True
309 return build_ext.initialize_options(self)
352 return build_ext.initialize_options(self)
310
353
311 def build_extensions(self):
354 def build_extensions(self):
312 # Filter out zstd if disabled via argument.
355 # Filter out zstd if disabled via argument.
313 if not self.zstd:
356 if not self.zstd:
314 self.extensions = [e for e in self.extensions
357 self.extensions = [e for e in self.extensions
315 if e.name != 'mercurial.zstd']
358 if e.name != 'mercurial.zstd']
316
359
317 return build_ext.build_extensions(self)
360 return build_ext.build_extensions(self)
318
361
319 def build_extension(self, ext):
362 def build_extension(self, ext):
320 try:
363 try:
321 build_ext.build_extension(self, ext)
364 build_ext.build_extension(self, ext)
322 except CCompilerError:
365 except CCompilerError:
323 if not getattr(ext, 'optional', False):
366 if not getattr(ext, 'optional', False):
324 raise
367 raise
325 log.warn("Failed to build optional extension '%s' (skipping)",
368 log.warn("Failed to build optional extension '%s' (skipping)",
326 ext.name)
369 ext.name)
327
370
328 class hgbuildscripts(build_scripts):
371 class hgbuildscripts(build_scripts):
329 def run(self):
372 def run(self):
330 if os.name != 'nt' or self.distribution.pure:
373 if os.name != 'nt' or self.distribution.pure:
331 return build_scripts.run(self)
374 return build_scripts.run(self)
332
375
333 exebuilt = False
376 exebuilt = False
334 try:
377 try:
335 self.run_command('build_hgexe')
378 self.run_command('build_hgexe')
336 exebuilt = True
379 exebuilt = True
337 except (DistutilsError, CCompilerError):
380 except (DistutilsError, CCompilerError):
338 log.warn('failed to build optional hg.exe')
381 log.warn('failed to build optional hg.exe')
339
382
340 if exebuilt:
383 if exebuilt:
341 # Copying hg.exe to the scripts build directory ensures it is
384 # Copying hg.exe to the scripts build directory ensures it is
342 # installed by the install_scripts command.
385 # installed by the install_scripts command.
343 hgexecommand = self.get_finalized_command('build_hgexe')
386 hgexecommand = self.get_finalized_command('build_hgexe')
344 dest = os.path.join(self.build_dir, 'hg.exe')
387 dest = os.path.join(self.build_dir, 'hg.exe')
345 self.mkpath(self.build_dir)
388 self.mkpath(self.build_dir)
346 self.copy_file(hgexecommand.hgexepath, dest)
389 self.copy_file(hgexecommand.hgexepath, dest)
347
390
348 # Remove hg.bat because it is redundant with hg.exe.
391 # Remove hg.bat because it is redundant with hg.exe.
349 self.scripts.remove('contrib/win32/hg.bat')
392 self.scripts.remove('contrib/win32/hg.bat')
350
393
351 return build_scripts.run(self)
394 return build_scripts.run(self)
352
395
353 class hgbuildpy(build_py):
396 class hgbuildpy(build_py):
354 def finalize_options(self):
397 def finalize_options(self):
355 build_py.finalize_options(self)
398 build_py.finalize_options(self)
356
399
357 if self.distribution.pure:
400 if self.distribution.pure:
358 self.distribution.ext_modules = []
401 self.distribution.ext_modules = []
359 elif self.distribution.cffi:
402 elif self.distribution.cffi:
360 from mercurial.cffi import (
403 from mercurial.cffi import (
361 bdiffbuild,
404 bdiffbuild,
362 mpatchbuild,
405 mpatchbuild,
363 )
406 )
364 exts = [mpatchbuild.ffi.distutils_extension(),
407 exts = [mpatchbuild.ffi.distutils_extension(),
365 bdiffbuild.ffi.distutils_extension()]
408 bdiffbuild.ffi.distutils_extension()]
366 # cffi modules go here
409 # cffi modules go here
367 if sys.platform == 'darwin':
410 if sys.platform == 'darwin':
368 from mercurial.cffi import osutilbuild
411 from mercurial.cffi import osutilbuild
369 exts.append(osutilbuild.ffi.distutils_extension())
412 exts.append(osutilbuild.ffi.distutils_extension())
370 self.distribution.ext_modules = exts
413 self.distribution.ext_modules = exts
371 else:
414 else:
372 h = os.path.join(get_python_inc(), 'Python.h')
415 h = os.path.join(get_python_inc(), 'Python.h')
373 if not os.path.exists(h):
416 if not os.path.exists(h):
374 raise SystemExit('Python headers are required to build '
417 raise SystemExit('Python headers are required to build '
375 'Mercurial but weren\'t found in %s' % h)
418 'Mercurial but weren\'t found in %s' % h)
376
419
377 def run(self):
420 def run(self):
378 basepath = os.path.join(self.build_lib, 'mercurial')
421 basepath = os.path.join(self.build_lib, 'mercurial')
379 self.mkpath(basepath)
422 self.mkpath(basepath)
380
423
381 if self.distribution.pure:
424 if self.distribution.pure:
382 modulepolicy = 'py'
425 modulepolicy = 'py'
383 elif self.build_lib == '.':
426 elif self.build_lib == '.':
384 # in-place build should run without rebuilding C extensions
427 # in-place build should run without rebuilding C extensions
385 modulepolicy = 'allow'
428 modulepolicy = 'allow'
386 else:
429 else:
387 modulepolicy = 'c'
430 modulepolicy = 'c'
388 with open(os.path.join(basepath, '__modulepolicy__.py'), "w") as f:
431 with open(os.path.join(basepath, '__modulepolicy__.py'), "w") as f:
389 f.write('# this file is autogenerated by setup.py\n')
432 f.write('# this file is autogenerated by setup.py\n')
390 f.write('modulepolicy = b"%s"\n' % modulepolicy)
433 f.write('modulepolicy = b"%s"\n' % modulepolicy)
391
434
392 build_py.run(self)
435 build_py.run(self)
393
436
394 class buildhgextindex(Command):
437 class buildhgextindex(Command):
395 description = 'generate prebuilt index of hgext (for frozen package)'
438 description = 'generate prebuilt index of hgext (for frozen package)'
396 user_options = []
439 user_options = []
397 _indexfilename = 'hgext/__index__.py'
440 _indexfilename = 'hgext/__index__.py'
398
441
399 def initialize_options(self):
442 def initialize_options(self):
400 pass
443 pass
401
444
402 def finalize_options(self):
445 def finalize_options(self):
403 pass
446 pass
404
447
405 def run(self):
448 def run(self):
406 if os.path.exists(self._indexfilename):
449 if os.path.exists(self._indexfilename):
407 with open(self._indexfilename, 'w') as f:
450 with open(self._indexfilename, 'w') as f:
408 f.write('# empty\n')
451 f.write('# empty\n')
409
452
410 # here no extension enabled, disabled() lists up everything
453 # here no extension enabled, disabled() lists up everything
411 code = ('import pprint; from mercurial import extensions; '
454 code = ('import pprint; from mercurial import extensions; '
412 'pprint.pprint(extensions.disabled())')
455 'pprint.pprint(extensions.disabled())')
413 returncode, out, err = runcmd([sys.executable, '-c', code], gethgenv())
456 returncode, out, err = runcmd([sys.executable, '-c', code],
457 localhgenv())
414 if err or returncode != 0:
458 if err or returncode != 0:
415 raise DistutilsExecError(err)
459 raise DistutilsExecError(err)
416
460
417 with open(self._indexfilename, 'w') as f:
461 with open(self._indexfilename, 'w') as f:
418 f.write('# this file is autogenerated by setup.py\n')
462 f.write('# this file is autogenerated by setup.py\n')
419 f.write('docs = ')
463 f.write('docs = ')
420 f.write(out)
464 f.write(out)
421
465
422 class buildhgexe(build_ext):
466 class buildhgexe(build_ext):
423 description = 'compile hg.exe from mercurial/exewrapper.c'
467 description = 'compile hg.exe from mercurial/exewrapper.c'
424
468
425 def build_extensions(self):
469 def build_extensions(self):
426 if os.name != 'nt':
470 if os.name != 'nt':
427 return
471 return
428 if isinstance(self.compiler, HackedMingw32CCompiler):
472 if isinstance(self.compiler, HackedMingw32CCompiler):
429 self.compiler.compiler_so = self.compiler.compiler # no -mdll
473 self.compiler.compiler_so = self.compiler.compiler # no -mdll
430 self.compiler.dll_libraries = [] # no -lmsrvc90
474 self.compiler.dll_libraries = [] # no -lmsrvc90
431
475
432 # Different Python installs can have different Python library
476 # Different Python installs can have different Python library
433 # names. e.g. the official CPython distribution uses pythonXY.dll
477 # names. e.g. the official CPython distribution uses pythonXY.dll
434 # and MinGW uses libpythonX.Y.dll.
478 # and MinGW uses libpythonX.Y.dll.
435 _kernel32 = ctypes.windll.kernel32
479 _kernel32 = ctypes.windll.kernel32
436 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
480 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
437 ctypes.c_void_p,
481 ctypes.c_void_p,
438 ctypes.c_ulong]
482 ctypes.c_ulong]
439 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
483 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
440 size = 1000
484 size = 1000
441 buf = ctypes.create_string_buffer(size + 1)
485 buf = ctypes.create_string_buffer(size + 1)
442 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
486 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
443 size)
487 size)
444
488
445 if filelen > 0 and filelen != size:
489 if filelen > 0 and filelen != size:
446 dllbasename = os.path.basename(buf.value)
490 dllbasename = os.path.basename(buf.value)
447 if not dllbasename.lower().endswith('.dll'):
491 if not dllbasename.lower().endswith('.dll'):
448 raise SystemExit('Python DLL does not end with .dll: %s' %
492 raise SystemExit('Python DLL does not end with .dll: %s' %
449 dllbasename)
493 dllbasename)
450 pythonlib = dllbasename[:-4]
494 pythonlib = dllbasename[:-4]
451 else:
495 else:
452 log.warn('could not determine Python DLL filename; '
496 log.warn('could not determine Python DLL filename; '
453 'assuming pythonXY')
497 'assuming pythonXY')
454
498
455 hv = sys.hexversion
499 hv = sys.hexversion
456 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
500 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
457
501
458 log.info('using %s as Python library name' % pythonlib)
502 log.info('using %s as Python library name' % pythonlib)
459 with open('mercurial/hgpythonlib.h', 'wb') as f:
503 with open('mercurial/hgpythonlib.h', 'wb') as f:
460 f.write('/* this file is autogenerated by setup.py */\n')
504 f.write('/* this file is autogenerated by setup.py */\n')
461 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
505 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
462 objects = self.compiler.compile(['mercurial/exewrapper.c'],
506 objects = self.compiler.compile(['mercurial/exewrapper.c'],
463 output_dir=self.build_temp)
507 output_dir=self.build_temp)
464 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
508 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
465 target = os.path.join(dir, 'hg')
509 target = os.path.join(dir, 'hg')
466 self.compiler.link_executable(objects, target,
510 self.compiler.link_executable(objects, target,
467 libraries=[],
511 libraries=[],
468 output_dir=self.build_temp)
512 output_dir=self.build_temp)
469
513
470 @property
514 @property
471 def hgexepath(self):
515 def hgexepath(self):
472 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
516 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
473 return os.path.join(self.build_temp, dir, 'hg.exe')
517 return os.path.join(self.build_temp, dir, 'hg.exe')
474
518
475 class hginstall(install):
519 class hginstall(install):
476
520
477 user_options = install.user_options + [
521 user_options = install.user_options + [
478 ('old-and-unmanageable', None,
522 ('old-and-unmanageable', None,
479 'noop, present for eggless setuptools compat'),
523 'noop, present for eggless setuptools compat'),
480 ('single-version-externally-managed', None,
524 ('single-version-externally-managed', None,
481 'noop, present for eggless setuptools compat'),
525 'noop, present for eggless setuptools compat'),
482 ]
526 ]
483
527
484 # Also helps setuptools not be sad while we refuse to create eggs.
528 # Also helps setuptools not be sad while we refuse to create eggs.
485 single_version_externally_managed = True
529 single_version_externally_managed = True
486
530
487 def get_sub_commands(self):
531 def get_sub_commands(self):
488 # Screen out egg related commands to prevent egg generation. But allow
532 # Screen out egg related commands to prevent egg generation. But allow
489 # mercurial.egg-info generation, since that is part of modern
533 # mercurial.egg-info generation, since that is part of modern
490 # packaging.
534 # packaging.
491 excl = {'bdist_egg'}
535 excl = {'bdist_egg'}
492 return filter(lambda x: x not in excl, install.get_sub_commands(self))
536 return filter(lambda x: x not in excl, install.get_sub_commands(self))
493
537
494 class hginstalllib(install_lib):
538 class hginstalllib(install_lib):
495 '''
539 '''
496 This is a specialization of install_lib that replaces the copy_file used
540 This is a specialization of install_lib that replaces the copy_file used
497 there so that it supports setting the mode of files after copying them,
541 there so that it supports setting the mode of files after copying them,
498 instead of just preserving the mode that the files originally had. If your
542 instead of just preserving the mode that the files originally had. If your
499 system has a umask of something like 027, preserving the permissions when
543 system has a umask of something like 027, preserving the permissions when
500 copying will lead to a broken install.
544 copying will lead to a broken install.
501
545
502 Note that just passing keep_permissions=False to copy_file would be
546 Note that just passing keep_permissions=False to copy_file would be
503 insufficient, as it might still be applying a umask.
547 insufficient, as it might still be applying a umask.
504 '''
548 '''
505
549
506 def run(self):
550 def run(self):
507 realcopyfile = file_util.copy_file
551 realcopyfile = file_util.copy_file
508 def copyfileandsetmode(*args, **kwargs):
552 def copyfileandsetmode(*args, **kwargs):
509 src, dst = args[0], args[1]
553 src, dst = args[0], args[1]
510 dst, copied = realcopyfile(*args, **kwargs)
554 dst, copied = realcopyfile(*args, **kwargs)
511 if copied:
555 if copied:
512 st = os.stat(src)
556 st = os.stat(src)
513 # Persist executable bit (apply it to group and other if user
557 # Persist executable bit (apply it to group and other if user
514 # has it)
558 # has it)
515 if st[stat.ST_MODE] & stat.S_IXUSR:
559 if st[stat.ST_MODE] & stat.S_IXUSR:
516 setmode = int('0755', 8)
560 setmode = int('0755', 8)
517 else:
561 else:
518 setmode = int('0644', 8)
562 setmode = int('0644', 8)
519 m = stat.S_IMODE(st[stat.ST_MODE])
563 m = stat.S_IMODE(st[stat.ST_MODE])
520 m = (m & ~int('0777', 8)) | setmode
564 m = (m & ~int('0777', 8)) | setmode
521 os.chmod(dst, m)
565 os.chmod(dst, m)
522 file_util.copy_file = copyfileandsetmode
566 file_util.copy_file = copyfileandsetmode
523 try:
567 try:
524 install_lib.run(self)
568 install_lib.run(self)
525 finally:
569 finally:
526 file_util.copy_file = realcopyfile
570 file_util.copy_file = realcopyfile
527
571
528 class hginstallscripts(install_scripts):
572 class hginstallscripts(install_scripts):
529 '''
573 '''
530 This is a specialization of install_scripts that replaces the @LIBDIR@ with
574 This is a specialization of install_scripts that replaces the @LIBDIR@ with
531 the configured directory for modules. If possible, the path is made relative
575 the configured directory for modules. If possible, the path is made relative
532 to the directory for scripts.
576 to the directory for scripts.
533 '''
577 '''
534
578
535 def initialize_options(self):
579 def initialize_options(self):
536 install_scripts.initialize_options(self)
580 install_scripts.initialize_options(self)
537
581
538 self.install_lib = None
582 self.install_lib = None
539
583
540 def finalize_options(self):
584 def finalize_options(self):
541 install_scripts.finalize_options(self)
585 install_scripts.finalize_options(self)
542 self.set_undefined_options('install',
586 self.set_undefined_options('install',
543 ('install_lib', 'install_lib'))
587 ('install_lib', 'install_lib'))
544
588
545 def run(self):
589 def run(self):
546 install_scripts.run(self)
590 install_scripts.run(self)
547
591
548 # It only makes sense to replace @LIBDIR@ with the install path if
592 # It only makes sense to replace @LIBDIR@ with the install path if
549 # the install path is known. For wheels, the logic below calculates
593 # the install path is known. For wheels, the logic below calculates
550 # the libdir to be "../..". This is because the internal layout of a
594 # the libdir to be "../..". This is because the internal layout of a
551 # wheel archive looks like:
595 # wheel archive looks like:
552 #
596 #
553 # mercurial-3.6.1.data/scripts/hg
597 # mercurial-3.6.1.data/scripts/hg
554 # mercurial/__init__.py
598 # mercurial/__init__.py
555 #
599 #
556 # When installing wheels, the subdirectories of the "<pkg>.data"
600 # When installing wheels, the subdirectories of the "<pkg>.data"
557 # directory are translated to system local paths and files therein
601 # directory are translated to system local paths and files therein
558 # are copied in place. The mercurial/* files are installed into the
602 # are copied in place. The mercurial/* files are installed into the
559 # site-packages directory. However, the site-packages directory
603 # site-packages directory. However, the site-packages directory
560 # isn't known until wheel install time. This means we have no clue
604 # isn't known until wheel install time. This means we have no clue
561 # at wheel generation time what the installed site-packages directory
605 # at wheel generation time what the installed site-packages directory
562 # will be. And, wheels don't appear to provide the ability to register
606 # will be. And, wheels don't appear to provide the ability to register
563 # custom code to run during wheel installation. This all means that
607 # custom code to run during wheel installation. This all means that
564 # we can't reliably set the libdir in wheels: the default behavior
608 # we can't reliably set the libdir in wheels: the default behavior
565 # of looking in sys.path must do.
609 # of looking in sys.path must do.
566
610
567 if (os.path.splitdrive(self.install_dir)[0] !=
611 if (os.path.splitdrive(self.install_dir)[0] !=
568 os.path.splitdrive(self.install_lib)[0]):
612 os.path.splitdrive(self.install_lib)[0]):
569 # can't make relative paths from one drive to another, so use an
613 # can't make relative paths from one drive to another, so use an
570 # absolute path instead
614 # absolute path instead
571 libdir = self.install_lib
615 libdir = self.install_lib
572 else:
616 else:
573 common = os.path.commonprefix((self.install_dir, self.install_lib))
617 common = os.path.commonprefix((self.install_dir, self.install_lib))
574 rest = self.install_dir[len(common):]
618 rest = self.install_dir[len(common):]
575 uplevel = len([n for n in os.path.split(rest) if n])
619 uplevel = len([n for n in os.path.split(rest) if n])
576
620
577 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
621 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
578
622
579 for outfile in self.outfiles:
623 for outfile in self.outfiles:
580 with open(outfile, 'rb') as fp:
624 with open(outfile, 'rb') as fp:
581 data = fp.read()
625 data = fp.read()
582
626
583 # skip binary files
627 # skip binary files
584 if b'\0' in data:
628 if b'\0' in data:
585 continue
629 continue
586
630
587 # During local installs, the shebang will be rewritten to the final
631 # During local installs, the shebang will be rewritten to the final
588 # install path. During wheel packaging, the shebang has a special
632 # install path. During wheel packaging, the shebang has a special
589 # value.
633 # value.
590 if data.startswith(b'#!python'):
634 if data.startswith(b'#!python'):
591 log.info('not rewriting @LIBDIR@ in %s because install path '
635 log.info('not rewriting @LIBDIR@ in %s because install path '
592 'not known' % outfile)
636 'not known' % outfile)
593 continue
637 continue
594
638
595 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
639 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
596 with open(outfile, 'wb') as fp:
640 with open(outfile, 'wb') as fp:
597 fp.write(data)
641 fp.write(data)
598
642
599 cmdclass = {'build': hgbuild,
643 cmdclass = {'build': hgbuild,
600 'build_mo': hgbuildmo,
644 'build_mo': hgbuildmo,
601 'build_ext': hgbuildext,
645 'build_ext': hgbuildext,
602 'build_py': hgbuildpy,
646 'build_py': hgbuildpy,
603 'build_scripts': hgbuildscripts,
647 'build_scripts': hgbuildscripts,
604 'build_hgextindex': buildhgextindex,
648 'build_hgextindex': buildhgextindex,
605 'install': hginstall,
649 'install': hginstall,
606 'install_lib': hginstalllib,
650 'install_lib': hginstalllib,
607 'install_scripts': hginstallscripts,
651 'install_scripts': hginstallscripts,
608 'build_hgexe': buildhgexe,
652 'build_hgexe': buildhgexe,
609 }
653 }
610
654
611 packages = ['mercurial',
655 packages = ['mercurial',
612 'mercurial.cext',
656 'mercurial.cext',
613 'mercurial.cffi',
657 'mercurial.cffi',
614 'mercurial.hgweb',
658 'mercurial.hgweb',
615 'mercurial.httpclient',
659 'mercurial.httpclient',
616 'mercurial.pure',
660 'mercurial.pure',
617 'hgext', 'hgext.convert', 'hgext.fsmonitor',
661 'hgext', 'hgext.convert', 'hgext.fsmonitor',
618 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
662 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
619 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd',
663 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd',
620 'hgdemandimport']
664 'hgdemandimport']
621
665
622 common_depends = ['mercurial/bitmanipulation.h',
666 common_depends = ['mercurial/bitmanipulation.h',
623 'mercurial/compat.h',
667 'mercurial/compat.h',
624 'mercurial/cext/util.h']
668 'mercurial/cext/util.h']
625 common_include_dirs = ['mercurial']
669 common_include_dirs = ['mercurial']
626
670
627 osutil_cflags = []
671 osutil_cflags = []
628 osutil_ldflags = []
672 osutil_ldflags = []
629
673
630 # platform specific macros
674 # platform specific macros
631 for plat, func in [('bsd', 'setproctitle')]:
675 for plat, func in [('bsd', 'setproctitle')]:
632 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
676 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
633 osutil_cflags.append('-DHAVE_%s' % func.upper())
677 osutil_cflags.append('-DHAVE_%s' % func.upper())
634
678
635 for plat, macro, code in [
679 for plat, macro, code in [
636 ('bsd|darwin', 'BSD_STATFS', '''
680 ('bsd|darwin', 'BSD_STATFS', '''
637 #include <sys/param.h>
681 #include <sys/param.h>
638 #include <sys/mount.h>
682 #include <sys/mount.h>
639 int main() { struct statfs s; return sizeof(s.f_fstypename); }
683 int main() { struct statfs s; return sizeof(s.f_fstypename); }
640 '''),
684 '''),
641 ('linux', 'LINUX_STATFS', '''
685 ('linux', 'LINUX_STATFS', '''
642 #include <linux/magic.h>
686 #include <linux/magic.h>
643 #include <sys/vfs.h>
687 #include <sys/vfs.h>
644 int main() { struct statfs s; return sizeof(s.f_type); }
688 int main() { struct statfs s; return sizeof(s.f_type); }
645 '''),
689 '''),
646 ]:
690 ]:
647 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
691 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
648 osutil_cflags.append('-DHAVE_%s' % macro)
692 osutil_cflags.append('-DHAVE_%s' % macro)
649
693
650 if sys.platform == 'darwin':
694 if sys.platform == 'darwin':
651 osutil_ldflags += ['-framework', 'ApplicationServices']
695 osutil_ldflags += ['-framework', 'ApplicationServices']
652
696
653 extmodules = [
697 extmodules = [
654 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'],
698 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'],
655 include_dirs=common_include_dirs,
699 include_dirs=common_include_dirs,
656 depends=common_depends),
700 depends=common_depends),
657 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c',
701 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c',
658 'mercurial/cext/bdiff.c'],
702 'mercurial/cext/bdiff.c'],
659 include_dirs=common_include_dirs,
703 include_dirs=common_include_dirs,
660 depends=common_depends + ['mercurial/bdiff.h']),
704 depends=common_depends + ['mercurial/bdiff.h']),
661 Extension('mercurial.cext.diffhelpers', ['mercurial/cext/diffhelpers.c'],
705 Extension('mercurial.cext.diffhelpers', ['mercurial/cext/diffhelpers.c'],
662 include_dirs=common_include_dirs,
706 include_dirs=common_include_dirs,
663 depends=common_depends),
707 depends=common_depends),
664 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c',
708 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c',
665 'mercurial/cext/mpatch.c'],
709 'mercurial/cext/mpatch.c'],
666 include_dirs=common_include_dirs,
710 include_dirs=common_include_dirs,
667 depends=common_depends),
711 depends=common_depends),
668 Extension('mercurial.cext.parsers', ['mercurial/cext/dirs.c',
712 Extension('mercurial.cext.parsers', ['mercurial/cext/dirs.c',
669 'mercurial/cext/manifest.c',
713 'mercurial/cext/manifest.c',
670 'mercurial/cext/parsers.c',
714 'mercurial/cext/parsers.c',
671 'mercurial/cext/pathencode.c',
715 'mercurial/cext/pathencode.c',
672 'mercurial/cext/revlog.c'],
716 'mercurial/cext/revlog.c'],
673 include_dirs=common_include_dirs,
717 include_dirs=common_include_dirs,
674 depends=common_depends),
718 depends=common_depends),
675 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'],
719 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'],
676 include_dirs=common_include_dirs,
720 include_dirs=common_include_dirs,
677 extra_compile_args=osutil_cflags,
721 extra_compile_args=osutil_cflags,
678 extra_link_args=osutil_ldflags,
722 extra_link_args=osutil_ldflags,
679 depends=common_depends),
723 depends=common_depends),
680 Extension('hgext.fsmonitor.pywatchman.bser',
724 Extension('hgext.fsmonitor.pywatchman.bser',
681 ['hgext/fsmonitor/pywatchman/bser.c']),
725 ['hgext/fsmonitor/pywatchman/bser.c']),
682 ]
726 ]
683
727
684 sys.path.insert(0, 'contrib/python-zstandard')
728 sys.path.insert(0, 'contrib/python-zstandard')
685 import setup_zstd
729 import setup_zstd
686 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
730 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
687
731
688 try:
732 try:
689 from distutils import cygwinccompiler
733 from distutils import cygwinccompiler
690
734
691 # the -mno-cygwin option has been deprecated for years
735 # the -mno-cygwin option has been deprecated for years
692 compiler = cygwinccompiler.Mingw32CCompiler
736 compiler = cygwinccompiler.Mingw32CCompiler
693
737
694 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
738 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
695 def __init__(self, *args, **kwargs):
739 def __init__(self, *args, **kwargs):
696 compiler.__init__(self, *args, **kwargs)
740 compiler.__init__(self, *args, **kwargs)
697 for i in 'compiler compiler_so linker_exe linker_so'.split():
741 for i in 'compiler compiler_so linker_exe linker_so'.split():
698 try:
742 try:
699 getattr(self, i).remove('-mno-cygwin')
743 getattr(self, i).remove('-mno-cygwin')
700 except ValueError:
744 except ValueError:
701 pass
745 pass
702
746
703 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
747 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
704 except ImportError:
748 except ImportError:
705 # the cygwinccompiler package is not available on some Python
749 # the cygwinccompiler package is not available on some Python
706 # distributions like the ones from the optware project for Synology
750 # distributions like the ones from the optware project for Synology
707 # DiskStation boxes
751 # DiskStation boxes
708 class HackedMingw32CCompiler(object):
752 class HackedMingw32CCompiler(object):
709 pass
753 pass
710
754
711 if os.name == 'nt':
755 if os.name == 'nt':
712 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
756 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
713 # extra_link_args to distutils.extensions.Extension() doesn't have any
757 # extra_link_args to distutils.extensions.Extension() doesn't have any
714 # effect.
758 # effect.
715 from distutils import msvccompiler
759 from distutils import msvccompiler
716
760
717 compiler = msvccompiler.MSVCCompiler
761 compiler = msvccompiler.MSVCCompiler
718
762
719 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
763 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
720 def initialize(self):
764 def initialize(self):
721 compiler.initialize(self)
765 compiler.initialize(self)
722 # "warning LNK4197: export 'func' specified multiple times"
766 # "warning LNK4197: export 'func' specified multiple times"
723 self.ldflags_shared.append('/ignore:4197')
767 self.ldflags_shared.append('/ignore:4197')
724 self.ldflags_shared_debug.append('/ignore:4197')
768 self.ldflags_shared_debug.append('/ignore:4197')
725
769
726 msvccompiler.MSVCCompiler = HackedMSVCCompiler
770 msvccompiler.MSVCCompiler = HackedMSVCCompiler
727
771
728 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
772 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
729 'help/*.txt',
773 'help/*.txt',
730 'help/internals/*.txt',
774 'help/internals/*.txt',
731 'default.d/*.rc',
775 'default.d/*.rc',
732 'dummycert.pem']}
776 'dummycert.pem']}
733
777
734 def ordinarypath(p):
778 def ordinarypath(p):
735 return p and p[0] != '.' and p[-1] != '~'
779 return p and p[0] != '.' and p[-1] != '~'
736
780
737 for root in ('templates',):
781 for root in ('templates',):
738 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
782 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
739 curdir = curdir.split(os.sep, 1)[1]
783 curdir = curdir.split(os.sep, 1)[1]
740 dirs[:] = filter(ordinarypath, dirs)
784 dirs[:] = filter(ordinarypath, dirs)
741 for f in filter(ordinarypath, files):
785 for f in filter(ordinarypath, files):
742 f = os.path.join(curdir, f)
786 f = os.path.join(curdir, f)
743 packagedata['mercurial'].append(f)
787 packagedata['mercurial'].append(f)
744
788
745 datafiles = []
789 datafiles = []
746
790
747 # distutils expects version to be str/unicode. Converting it to
791 # distutils expects version to be str/unicode. Converting it to
748 # unicode on Python 2 still works because it won't contain any
792 # unicode on Python 2 still works because it won't contain any
749 # non-ascii bytes and will be implicitly converted back to bytes
793 # non-ascii bytes and will be implicitly converted back to bytes
750 # when operated on.
794 # when operated on.
751 assert isinstance(version, bytes)
795 assert isinstance(version, bytes)
752 setupversion = version.decode('ascii')
796 setupversion = version.decode('ascii')
753
797
754 extra = {}
798 extra = {}
755
799
756 if py2exeloaded:
800 if py2exeloaded:
757 extra['console'] = [
801 extra['console'] = [
758 {'script':'hg',
802 {'script':'hg',
759 'copyright':'Copyright (C) 2005-2017 Matt Mackall and others',
803 'copyright':'Copyright (C) 2005-2017 Matt Mackall and others',
760 'product_version':version}]
804 'product_version':version}]
761 # sub command of 'build' because 'py2exe' does not handle sub_commands
805 # sub command of 'build' because 'py2exe' does not handle sub_commands
762 build.sub_commands.insert(0, ('build_hgextindex', None))
806 build.sub_commands.insert(0, ('build_hgextindex', None))
763 # put dlls in sub directory so that they won't pollute PATH
807 # put dlls in sub directory so that they won't pollute PATH
764 extra['zipfile'] = 'lib/library.zip'
808 extra['zipfile'] = 'lib/library.zip'
765
809
766 if os.name == 'nt':
810 if os.name == 'nt':
767 # Windows binary file versions for exe/dll files must have the
811 # Windows binary file versions for exe/dll files must have the
768 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
812 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
769 setupversion = version.split('+', 1)[0]
813 setupversion = version.split('+', 1)[0]
770
814
771 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
815 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
772 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
816 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
773 if version:
817 if version:
774 version = version[0]
818 version = version[0]
775 if sys.version_info[0] == 3:
819 if sys.version_info[0] == 3:
776 version = version.decode('utf-8')
820 version = version.decode('utf-8')
777 xcode4 = (version.startswith('Xcode') and
821 xcode4 = (version.startswith('Xcode') and
778 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
822 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
779 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
823 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
780 else:
824 else:
781 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
825 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
782 # installed, but instead with only command-line tools. Assume
826 # installed, but instead with only command-line tools. Assume
783 # that only happens on >= Lion, thus no PPC support.
827 # that only happens on >= Lion, thus no PPC support.
784 xcode4 = True
828 xcode4 = True
785 xcode51 = False
829 xcode51 = False
786
830
787 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
831 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
788 # distutils.sysconfig
832 # distutils.sysconfig
789 if xcode4:
833 if xcode4:
790 os.environ['ARCHFLAGS'] = ''
834 os.environ['ARCHFLAGS'] = ''
791
835
792 # XCode 5.1 changes clang such that it now fails to compile if the
836 # XCode 5.1 changes clang such that it now fails to compile if the
793 # -mno-fused-madd flag is passed, but the version of Python shipped with
837 # -mno-fused-madd flag is passed, but the version of Python shipped with
794 # OS X 10.9 Mavericks includes this flag. This causes problems in all
838 # OS X 10.9 Mavericks includes this flag. This causes problems in all
795 # C extension modules, and a bug has been filed upstream at
839 # C extension modules, and a bug has been filed upstream at
796 # http://bugs.python.org/issue21244. We also need to patch this here
840 # http://bugs.python.org/issue21244. We also need to patch this here
797 # so Mercurial can continue to compile in the meantime.
841 # so Mercurial can continue to compile in the meantime.
798 if xcode51:
842 if xcode51:
799 cflags = get_config_var('CFLAGS')
843 cflags = get_config_var('CFLAGS')
800 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
844 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
801 os.environ['CFLAGS'] = (
845 os.environ['CFLAGS'] = (
802 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
846 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
803
847
804 setup(name='mercurial',
848 setup(name='mercurial',
805 version=setupversion,
849 version=setupversion,
806 author='Matt Mackall and many others',
850 author='Matt Mackall and many others',
807 author_email='mercurial@mercurial-scm.org',
851 author_email='mercurial@mercurial-scm.org',
808 url='https://mercurial-scm.org/',
852 url='https://mercurial-scm.org/',
809 download_url='https://mercurial-scm.org/release/',
853 download_url='https://mercurial-scm.org/release/',
810 description=('Fast scalable distributed SCM (revision control, version '
854 description=('Fast scalable distributed SCM (revision control, version '
811 'control) system'),
855 'control) system'),
812 long_description=('Mercurial is a distributed SCM tool written in Python.'
856 long_description=('Mercurial is a distributed SCM tool written in Python.'
813 ' It is used by a number of large projects that require'
857 ' It is used by a number of large projects that require'
814 ' fast, reliable distributed revision control, such as '
858 ' fast, reliable distributed revision control, such as '
815 'Mozilla.'),
859 'Mozilla.'),
816 license='GNU GPLv2 or any later version',
860 license='GNU GPLv2 or any later version',
817 classifiers=[
861 classifiers=[
818 'Development Status :: 6 - Mature',
862 'Development Status :: 6 - Mature',
819 'Environment :: Console',
863 'Environment :: Console',
820 'Intended Audience :: Developers',
864 'Intended Audience :: Developers',
821 'Intended Audience :: System Administrators',
865 'Intended Audience :: System Administrators',
822 'License :: OSI Approved :: GNU General Public License (GPL)',
866 'License :: OSI Approved :: GNU General Public License (GPL)',
823 'Natural Language :: Danish',
867 'Natural Language :: Danish',
824 'Natural Language :: English',
868 'Natural Language :: English',
825 'Natural Language :: German',
869 'Natural Language :: German',
826 'Natural Language :: Italian',
870 'Natural Language :: Italian',
827 'Natural Language :: Japanese',
871 'Natural Language :: Japanese',
828 'Natural Language :: Portuguese (Brazilian)',
872 'Natural Language :: Portuguese (Brazilian)',
829 'Operating System :: Microsoft :: Windows',
873 'Operating System :: Microsoft :: Windows',
830 'Operating System :: OS Independent',
874 'Operating System :: OS Independent',
831 'Operating System :: POSIX',
875 'Operating System :: POSIX',
832 'Programming Language :: C',
876 'Programming Language :: C',
833 'Programming Language :: Python',
877 'Programming Language :: Python',
834 'Topic :: Software Development :: Version Control',
878 'Topic :: Software Development :: Version Control',
835 ],
879 ],
836 scripts=scripts,
880 scripts=scripts,
837 packages=packages,
881 packages=packages,
838 ext_modules=extmodules,
882 ext_modules=extmodules,
839 data_files=datafiles,
883 data_files=datafiles,
840 package_data=packagedata,
884 package_data=packagedata,
841 cmdclass=cmdclass,
885 cmdclass=cmdclass,
842 distclass=hgdist,
886 distclass=hgdist,
843 options={'py2exe': {'packages': ['hgdemandimport', 'hgext', 'email']},
887 options={'py2exe': {'packages': ['hgdemandimport', 'hgext', 'email']},
844 'bdist_mpkg': {'zipdist': False,
888 'bdist_mpkg': {'zipdist': False,
845 'license': 'COPYING',
889 'license': 'COPYING',
846 'readme': 'contrib/macosx/Readme.html',
890 'readme': 'contrib/macosx/Readme.html',
847 'welcome': 'contrib/macosx/Welcome.html',
891 'welcome': 'contrib/macosx/Welcome.html',
848 },
892 },
849 },
893 },
850 **extra)
894 **extra)
General Comments 0
You need to be logged in to leave comments. Login now