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