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