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