##// END OF EJS Templates
setup: test some header files...
Jun Wu -
r31562:3db113ee default
parent child Browse files
Show More
@@ -1,774 +1,784 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 getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.6 or later.")
9 raise SystemExit("Mercurial requires Python 2.6 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 else:
375 else:
376 modulepolicy = 'c'
376 modulepolicy = 'c'
377 with open("mercurial/__modulepolicy__.py", "w") as f:
377 with open("mercurial/__modulepolicy__.py", "w") as f:
378 f.write('# this file is autogenerated by setup.py\n')
378 f.write('# this file is autogenerated by setup.py\n')
379 f.write('modulepolicy = b"%s"\n' % modulepolicy)
379 f.write('modulepolicy = b"%s"\n' % modulepolicy)
380
380
381 build_py.run(self)
381 build_py.run(self)
382
382
383 class buildhgextindex(Command):
383 class buildhgextindex(Command):
384 description = 'generate prebuilt index of hgext (for frozen package)'
384 description = 'generate prebuilt index of hgext (for frozen package)'
385 user_options = []
385 user_options = []
386 _indexfilename = 'hgext/__index__.py'
386 _indexfilename = 'hgext/__index__.py'
387
387
388 def initialize_options(self):
388 def initialize_options(self):
389 pass
389 pass
390
390
391 def finalize_options(self):
391 def finalize_options(self):
392 pass
392 pass
393
393
394 def run(self):
394 def run(self):
395 if os.path.exists(self._indexfilename):
395 if os.path.exists(self._indexfilename):
396 with open(self._indexfilename, 'w') as f:
396 with open(self._indexfilename, 'w') as f:
397 f.write('# empty\n')
397 f.write('# empty\n')
398
398
399 # here no extension enabled, disabled() lists up everything
399 # here no extension enabled, disabled() lists up everything
400 code = ('import pprint; from mercurial import extensions; '
400 code = ('import pprint; from mercurial import extensions; '
401 'pprint.pprint(extensions.disabled())')
401 'pprint.pprint(extensions.disabled())')
402 out, err = runcmd([sys.executable, '-c', code], env)
402 out, err = runcmd([sys.executable, '-c', code], env)
403 if err:
403 if err:
404 raise DistutilsExecError(err)
404 raise DistutilsExecError(err)
405
405
406 with open(self._indexfilename, 'w') as f:
406 with open(self._indexfilename, 'w') as f:
407 f.write('# this file is autogenerated by setup.py\n')
407 f.write('# this file is autogenerated by setup.py\n')
408 f.write('docs = ')
408 f.write('docs = ')
409 f.write(out)
409 f.write(out)
410
410
411 class buildhgexe(build_ext):
411 class buildhgexe(build_ext):
412 description = 'compile hg.exe from mercurial/exewrapper.c'
412 description = 'compile hg.exe from mercurial/exewrapper.c'
413
413
414 def build_extensions(self):
414 def build_extensions(self):
415 if os.name != 'nt':
415 if os.name != 'nt':
416 return
416 return
417 if isinstance(self.compiler, HackedMingw32CCompiler):
417 if isinstance(self.compiler, HackedMingw32CCompiler):
418 self.compiler.compiler_so = self.compiler.compiler # no -mdll
418 self.compiler.compiler_so = self.compiler.compiler # no -mdll
419 self.compiler.dll_libraries = [] # no -lmsrvc90
419 self.compiler.dll_libraries = [] # no -lmsrvc90
420
420
421 # Different Python installs can have different Python library
421 # Different Python installs can have different Python library
422 # names. e.g. the official CPython distribution uses pythonXY.dll
422 # names. e.g. the official CPython distribution uses pythonXY.dll
423 # and MinGW uses libpythonX.Y.dll.
423 # and MinGW uses libpythonX.Y.dll.
424 _kernel32 = ctypes.windll.kernel32
424 _kernel32 = ctypes.windll.kernel32
425 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
425 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
426 ctypes.c_void_p,
426 ctypes.c_void_p,
427 ctypes.c_ulong]
427 ctypes.c_ulong]
428 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
428 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
429 size = 1000
429 size = 1000
430 buf = ctypes.create_string_buffer(size + 1)
430 buf = ctypes.create_string_buffer(size + 1)
431 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
431 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
432 size)
432 size)
433
433
434 if filelen > 0 and filelen != size:
434 if filelen > 0 and filelen != size:
435 dllbasename = os.path.basename(buf.value)
435 dllbasename = os.path.basename(buf.value)
436 if not dllbasename.lower().endswith('.dll'):
436 if not dllbasename.lower().endswith('.dll'):
437 raise SystemExit('Python DLL does not end with .dll: %s' %
437 raise SystemExit('Python DLL does not end with .dll: %s' %
438 dllbasename)
438 dllbasename)
439 pythonlib = dllbasename[:-4]
439 pythonlib = dllbasename[:-4]
440 else:
440 else:
441 log.warn('could not determine Python DLL filename; '
441 log.warn('could not determine Python DLL filename; '
442 'assuming pythonXY')
442 'assuming pythonXY')
443
443
444 hv = sys.hexversion
444 hv = sys.hexversion
445 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
445 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
446
446
447 log.info('using %s as Python library name' % pythonlib)
447 log.info('using %s as Python library name' % pythonlib)
448 with open('mercurial/hgpythonlib.h', 'wb') as f:
448 with open('mercurial/hgpythonlib.h', 'wb') as f:
449 f.write('/* this file is autogenerated by setup.py */\n')
449 f.write('/* this file is autogenerated by setup.py */\n')
450 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
450 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
451 objects = self.compiler.compile(['mercurial/exewrapper.c'],
451 objects = self.compiler.compile(['mercurial/exewrapper.c'],
452 output_dir=self.build_temp)
452 output_dir=self.build_temp)
453 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
453 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
454 target = os.path.join(dir, 'hg')
454 target = os.path.join(dir, 'hg')
455 self.compiler.link_executable(objects, target,
455 self.compiler.link_executable(objects, target,
456 libraries=[],
456 libraries=[],
457 output_dir=self.build_temp)
457 output_dir=self.build_temp)
458
458
459 @property
459 @property
460 def hgexepath(self):
460 def hgexepath(self):
461 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
461 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
462 return os.path.join(self.build_temp, dir, 'hg.exe')
462 return os.path.join(self.build_temp, dir, 'hg.exe')
463
463
464 class hginstalllib(install_lib):
464 class hginstalllib(install_lib):
465 '''
465 '''
466 This is a specialization of install_lib that replaces the copy_file used
466 This is a specialization of install_lib that replaces the copy_file used
467 there so that it supports setting the mode of files after copying them,
467 there so that it supports setting the mode of files after copying them,
468 instead of just preserving the mode that the files originally had. If your
468 instead of just preserving the mode that the files originally had. If your
469 system has a umask of something like 027, preserving the permissions when
469 system has a umask of something like 027, preserving the permissions when
470 copying will lead to a broken install.
470 copying will lead to a broken install.
471
471
472 Note that just passing keep_permissions=False to copy_file would be
472 Note that just passing keep_permissions=False to copy_file would be
473 insufficient, as it might still be applying a umask.
473 insufficient, as it might still be applying a umask.
474 '''
474 '''
475
475
476 def run(self):
476 def run(self):
477 realcopyfile = file_util.copy_file
477 realcopyfile = file_util.copy_file
478 def copyfileandsetmode(*args, **kwargs):
478 def copyfileandsetmode(*args, **kwargs):
479 src, dst = args[0], args[1]
479 src, dst = args[0], args[1]
480 dst, copied = realcopyfile(*args, **kwargs)
480 dst, copied = realcopyfile(*args, **kwargs)
481 if copied:
481 if copied:
482 st = os.stat(src)
482 st = os.stat(src)
483 # Persist executable bit (apply it to group and other if user
483 # Persist executable bit (apply it to group and other if user
484 # has it)
484 # has it)
485 if st[stat.ST_MODE] & stat.S_IXUSR:
485 if st[stat.ST_MODE] & stat.S_IXUSR:
486 setmode = int('0755', 8)
486 setmode = int('0755', 8)
487 else:
487 else:
488 setmode = int('0644', 8)
488 setmode = int('0644', 8)
489 m = stat.S_IMODE(st[stat.ST_MODE])
489 m = stat.S_IMODE(st[stat.ST_MODE])
490 m = (m & ~int('0777', 8)) | setmode
490 m = (m & ~int('0777', 8)) | setmode
491 os.chmod(dst, m)
491 os.chmod(dst, m)
492 file_util.copy_file = copyfileandsetmode
492 file_util.copy_file = copyfileandsetmode
493 try:
493 try:
494 install_lib.run(self)
494 install_lib.run(self)
495 finally:
495 finally:
496 file_util.copy_file = realcopyfile
496 file_util.copy_file = realcopyfile
497
497
498 class hginstallscripts(install_scripts):
498 class hginstallscripts(install_scripts):
499 '''
499 '''
500 This is a specialization of install_scripts that replaces the @LIBDIR@ with
500 This is a specialization of install_scripts that replaces the @LIBDIR@ with
501 the configured directory for modules. If possible, the path is made relative
501 the configured directory for modules. If possible, the path is made relative
502 to the directory for scripts.
502 to the directory for scripts.
503 '''
503 '''
504
504
505 def initialize_options(self):
505 def initialize_options(self):
506 install_scripts.initialize_options(self)
506 install_scripts.initialize_options(self)
507
507
508 self.install_lib = None
508 self.install_lib = None
509
509
510 def finalize_options(self):
510 def finalize_options(self):
511 install_scripts.finalize_options(self)
511 install_scripts.finalize_options(self)
512 self.set_undefined_options('install',
512 self.set_undefined_options('install',
513 ('install_lib', 'install_lib'))
513 ('install_lib', 'install_lib'))
514
514
515 def run(self):
515 def run(self):
516 install_scripts.run(self)
516 install_scripts.run(self)
517
517
518 # It only makes sense to replace @LIBDIR@ with the install path if
518 # It only makes sense to replace @LIBDIR@ with the install path if
519 # the install path is known. For wheels, the logic below calculates
519 # the install path is known. For wheels, the logic below calculates
520 # the libdir to be "../..". This is because the internal layout of a
520 # the libdir to be "../..". This is because the internal layout of a
521 # wheel archive looks like:
521 # wheel archive looks like:
522 #
522 #
523 # mercurial-3.6.1.data/scripts/hg
523 # mercurial-3.6.1.data/scripts/hg
524 # mercurial/__init__.py
524 # mercurial/__init__.py
525 #
525 #
526 # When installing wheels, the subdirectories of the "<pkg>.data"
526 # When installing wheels, the subdirectories of the "<pkg>.data"
527 # directory are translated to system local paths and files therein
527 # directory are translated to system local paths and files therein
528 # are copied in place. The mercurial/* files are installed into the
528 # are copied in place. The mercurial/* files are installed into the
529 # site-packages directory. However, the site-packages directory
529 # site-packages directory. However, the site-packages directory
530 # isn't known until wheel install time. This means we have no clue
530 # isn't known until wheel install time. This means we have no clue
531 # at wheel generation time what the installed site-packages directory
531 # at wheel generation time what the installed site-packages directory
532 # will be. And, wheels don't appear to provide the ability to register
532 # will be. And, wheels don't appear to provide the ability to register
533 # custom code to run during wheel installation. This all means that
533 # custom code to run during wheel installation. This all means that
534 # we can't reliably set the libdir in wheels: the default behavior
534 # we can't reliably set the libdir in wheels: the default behavior
535 # of looking in sys.path must do.
535 # of looking in sys.path must do.
536
536
537 if (os.path.splitdrive(self.install_dir)[0] !=
537 if (os.path.splitdrive(self.install_dir)[0] !=
538 os.path.splitdrive(self.install_lib)[0]):
538 os.path.splitdrive(self.install_lib)[0]):
539 # can't make relative paths from one drive to another, so use an
539 # can't make relative paths from one drive to another, so use an
540 # absolute path instead
540 # absolute path instead
541 libdir = self.install_lib
541 libdir = self.install_lib
542 else:
542 else:
543 common = os.path.commonprefix((self.install_dir, self.install_lib))
543 common = os.path.commonprefix((self.install_dir, self.install_lib))
544 rest = self.install_dir[len(common):]
544 rest = self.install_dir[len(common):]
545 uplevel = len([n for n in os.path.split(rest) if n])
545 uplevel = len([n for n in os.path.split(rest) if n])
546
546
547 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
547 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
548
548
549 for outfile in self.outfiles:
549 for outfile in self.outfiles:
550 with open(outfile, 'rb') as fp:
550 with open(outfile, 'rb') as fp:
551 data = fp.read()
551 data = fp.read()
552
552
553 # skip binary files
553 # skip binary files
554 if b'\0' in data:
554 if b'\0' in data:
555 continue
555 continue
556
556
557 # During local installs, the shebang will be rewritten to the final
557 # During local installs, the shebang will be rewritten to the final
558 # install path. During wheel packaging, the shebang has a special
558 # install path. During wheel packaging, the shebang has a special
559 # value.
559 # value.
560 if data.startswith(b'#!python'):
560 if data.startswith(b'#!python'):
561 log.info('not rewriting @LIBDIR@ in %s because install path '
561 log.info('not rewriting @LIBDIR@ in %s because install path '
562 'not known' % outfile)
562 'not known' % outfile)
563 continue
563 continue
564
564
565 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
565 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
566 with open(outfile, 'wb') as fp:
566 with open(outfile, 'wb') as fp:
567 fp.write(data)
567 fp.write(data)
568
568
569 cmdclass = {'build': hgbuild,
569 cmdclass = {'build': hgbuild,
570 'build_mo': hgbuildmo,
570 'build_mo': hgbuildmo,
571 'build_ext': hgbuildext,
571 'build_ext': hgbuildext,
572 'build_py': hgbuildpy,
572 'build_py': hgbuildpy,
573 'build_scripts': hgbuildscripts,
573 'build_scripts': hgbuildscripts,
574 'build_hgextindex': buildhgextindex,
574 'build_hgextindex': buildhgextindex,
575 'install_lib': hginstalllib,
575 'install_lib': hginstalllib,
576 'install_scripts': hginstallscripts,
576 'install_scripts': hginstallscripts,
577 'build_hgexe': buildhgexe,
577 'build_hgexe': buildhgexe,
578 }
578 }
579
579
580 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
580 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
581 'mercurial.pure',
581 'mercurial.pure',
582 'hgext', 'hgext.convert', 'hgext.fsmonitor',
582 'hgext', 'hgext.convert', 'hgext.fsmonitor',
583 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
583 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
584 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd']
584 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd']
585
585
586 common_depends = ['mercurial/bitmanipulation.h',
586 common_depends = ['mercurial/bitmanipulation.h',
587 'mercurial/compat.h',
587 'mercurial/compat.h',
588 'mercurial/util.h']
588 'mercurial/util.h']
589
589
590 osutil_cflags = []
590 osutil_cflags = []
591 osutil_ldflags = []
591 osutil_ldflags = []
592
592
593 # platform specific macros
593 # platform specific macros
594 for plat, func in [('bsd', 'setproctitle'), ('bsd|darwin|linux', 'statfs')]:
594 for plat, func in [('bsd', 'setproctitle'), ('bsd|darwin|linux', 'statfs')]:
595 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
595 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
596 osutil_cflags.append('-DHAVE_%s' % func.upper())
596 osutil_cflags.append('-DHAVE_%s' % func.upper())
597
597
598 for plat, header in [
599 ('bsd|darwin|linux', 'sys/mount.h'),
600 ('bsd|darwin|linux', 'sys/param.h'),
601 ('linux', 'linux/magic.h'),
602 ('linux', 'sys/vfs.h'),
603 ]:
604 if re.search(plat, sys.platform) and hasheader(new_compiler(), header):
605 macro = header.replace('/', '_').replace('.', '_').upper()
606 osutil_cflags.append('-DHAVE_%s' % macro)
607
598 if sys.platform == 'darwin':
608 if sys.platform == 'darwin':
599 osutil_ldflags += ['-framework', 'ApplicationServices']
609 osutil_ldflags += ['-framework', 'ApplicationServices']
600
610
601 extmodules = [
611 extmodules = [
602 Extension('mercurial.base85', ['mercurial/base85.c'],
612 Extension('mercurial.base85', ['mercurial/base85.c'],
603 depends=common_depends),
613 depends=common_depends),
604 Extension('mercurial.bdiff', ['mercurial/bdiff.c',
614 Extension('mercurial.bdiff', ['mercurial/bdiff.c',
605 'mercurial/bdiff_module.c'],
615 'mercurial/bdiff_module.c'],
606 depends=common_depends + ['mercurial/bdiff.h']),
616 depends=common_depends + ['mercurial/bdiff.h']),
607 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
617 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
608 depends=common_depends),
618 depends=common_depends),
609 Extension('mercurial.mpatch', ['mercurial/mpatch.c',
619 Extension('mercurial.mpatch', ['mercurial/mpatch.c',
610 'mercurial/mpatch_module.c'],
620 'mercurial/mpatch_module.c'],
611 depends=common_depends),
621 depends=common_depends),
612 Extension('mercurial.parsers', ['mercurial/dirs.c',
622 Extension('mercurial.parsers', ['mercurial/dirs.c',
613 'mercurial/manifest.c',
623 'mercurial/manifest.c',
614 'mercurial/parsers.c',
624 'mercurial/parsers.c',
615 'mercurial/pathencode.c'],
625 'mercurial/pathencode.c'],
616 depends=common_depends),
626 depends=common_depends),
617 Extension('mercurial.osutil', ['mercurial/osutil.c'],
627 Extension('mercurial.osutil', ['mercurial/osutil.c'],
618 extra_compile_args=osutil_cflags,
628 extra_compile_args=osutil_cflags,
619 extra_link_args=osutil_ldflags,
629 extra_link_args=osutil_ldflags,
620 depends=common_depends),
630 depends=common_depends),
621 Extension('hgext.fsmonitor.pywatchman.bser',
631 Extension('hgext.fsmonitor.pywatchman.bser',
622 ['hgext/fsmonitor/pywatchman/bser.c']),
632 ['hgext/fsmonitor/pywatchman/bser.c']),
623 ]
633 ]
624
634
625 sys.path.insert(0, 'contrib/python-zstandard')
635 sys.path.insert(0, 'contrib/python-zstandard')
626 import setup_zstd
636 import setup_zstd
627 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
637 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
628
638
629 try:
639 try:
630 from distutils import cygwinccompiler
640 from distutils import cygwinccompiler
631
641
632 # the -mno-cygwin option has been deprecated for years
642 # the -mno-cygwin option has been deprecated for years
633 compiler = cygwinccompiler.Mingw32CCompiler
643 compiler = cygwinccompiler.Mingw32CCompiler
634
644
635 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
645 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
636 def __init__(self, *args, **kwargs):
646 def __init__(self, *args, **kwargs):
637 compiler.__init__(self, *args, **kwargs)
647 compiler.__init__(self, *args, **kwargs)
638 for i in 'compiler compiler_so linker_exe linker_so'.split():
648 for i in 'compiler compiler_so linker_exe linker_so'.split():
639 try:
649 try:
640 getattr(self, i).remove('-mno-cygwin')
650 getattr(self, i).remove('-mno-cygwin')
641 except ValueError:
651 except ValueError:
642 pass
652 pass
643
653
644 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
654 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
645 except ImportError:
655 except ImportError:
646 # the cygwinccompiler package is not available on some Python
656 # the cygwinccompiler package is not available on some Python
647 # distributions like the ones from the optware project for Synology
657 # distributions like the ones from the optware project for Synology
648 # DiskStation boxes
658 # DiskStation boxes
649 class HackedMingw32CCompiler(object):
659 class HackedMingw32CCompiler(object):
650 pass
660 pass
651
661
652 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
662 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
653 'help/*.txt',
663 'help/*.txt',
654 'help/internals/*.txt',
664 'help/internals/*.txt',
655 'default.d/*.rc',
665 'default.d/*.rc',
656 'dummycert.pem']}
666 'dummycert.pem']}
657
667
658 def ordinarypath(p):
668 def ordinarypath(p):
659 return p and p[0] != '.' and p[-1] != '~'
669 return p and p[0] != '.' and p[-1] != '~'
660
670
661 for root in ('templates',):
671 for root in ('templates',):
662 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
672 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
663 curdir = curdir.split(os.sep, 1)[1]
673 curdir = curdir.split(os.sep, 1)[1]
664 dirs[:] = filter(ordinarypath, dirs)
674 dirs[:] = filter(ordinarypath, dirs)
665 for f in filter(ordinarypath, files):
675 for f in filter(ordinarypath, files):
666 f = os.path.join(curdir, f)
676 f = os.path.join(curdir, f)
667 packagedata['mercurial'].append(f)
677 packagedata['mercurial'].append(f)
668
678
669 datafiles = []
679 datafiles = []
670
680
671 # distutils expects version to be str/unicode. Converting it to
681 # distutils expects version to be str/unicode. Converting it to
672 # unicode on Python 2 still works because it won't contain any
682 # unicode on Python 2 still works because it won't contain any
673 # non-ascii bytes and will be implicitly converted back to bytes
683 # non-ascii bytes and will be implicitly converted back to bytes
674 # when operated on.
684 # when operated on.
675 assert isinstance(version, bytes)
685 assert isinstance(version, bytes)
676 setupversion = version.decode('ascii')
686 setupversion = version.decode('ascii')
677
687
678 extra = {}
688 extra = {}
679
689
680 if py2exeloaded:
690 if py2exeloaded:
681 extra['console'] = [
691 extra['console'] = [
682 {'script':'hg',
692 {'script':'hg',
683 'copyright':'Copyright (C) 2005-2017 Matt Mackall and others',
693 'copyright':'Copyright (C) 2005-2017 Matt Mackall and others',
684 'product_version':version}]
694 'product_version':version}]
685 # sub command of 'build' because 'py2exe' does not handle sub_commands
695 # sub command of 'build' because 'py2exe' does not handle sub_commands
686 build.sub_commands.insert(0, ('build_hgextindex', None))
696 build.sub_commands.insert(0, ('build_hgextindex', None))
687 # put dlls in sub directory so that they won't pollute PATH
697 # put dlls in sub directory so that they won't pollute PATH
688 extra['zipfile'] = 'lib/library.zip'
698 extra['zipfile'] = 'lib/library.zip'
689
699
690 if os.name == 'nt':
700 if os.name == 'nt':
691 # Windows binary file versions for exe/dll files must have the
701 # Windows binary file versions for exe/dll files must have the
692 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
702 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
693 setupversion = version.split('+', 1)[0]
703 setupversion = version.split('+', 1)[0]
694
704
695 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
705 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
696 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
706 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
697 if version:
707 if version:
698 version = version[0]
708 version = version[0]
699 if sys.version_info[0] == 3:
709 if sys.version_info[0] == 3:
700 version = version.decode('utf-8')
710 version = version.decode('utf-8')
701 xcode4 = (version.startswith('Xcode') and
711 xcode4 = (version.startswith('Xcode') and
702 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
712 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
703 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
713 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
704 else:
714 else:
705 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
715 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
706 # installed, but instead with only command-line tools. Assume
716 # installed, but instead with only command-line tools. Assume
707 # that only happens on >= Lion, thus no PPC support.
717 # that only happens on >= Lion, thus no PPC support.
708 xcode4 = True
718 xcode4 = True
709 xcode51 = False
719 xcode51 = False
710
720
711 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
721 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
712 # distutils.sysconfig
722 # distutils.sysconfig
713 if xcode4:
723 if xcode4:
714 os.environ['ARCHFLAGS'] = ''
724 os.environ['ARCHFLAGS'] = ''
715
725
716 # XCode 5.1 changes clang such that it now fails to compile if the
726 # XCode 5.1 changes clang such that it now fails to compile if the
717 # -mno-fused-madd flag is passed, but the version of Python shipped with
727 # -mno-fused-madd flag is passed, but the version of Python shipped with
718 # OS X 10.9 Mavericks includes this flag. This causes problems in all
728 # OS X 10.9 Mavericks includes this flag. This causes problems in all
719 # C extension modules, and a bug has been filed upstream at
729 # C extension modules, and a bug has been filed upstream at
720 # http://bugs.python.org/issue21244. We also need to patch this here
730 # http://bugs.python.org/issue21244. We also need to patch this here
721 # so Mercurial can continue to compile in the meantime.
731 # so Mercurial can continue to compile in the meantime.
722 if xcode51:
732 if xcode51:
723 cflags = get_config_var('CFLAGS')
733 cflags = get_config_var('CFLAGS')
724 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
734 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
725 os.environ['CFLAGS'] = (
735 os.environ['CFLAGS'] = (
726 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
736 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
727
737
728 setup(name='mercurial',
738 setup(name='mercurial',
729 version=setupversion,
739 version=setupversion,
730 author='Matt Mackall and many others',
740 author='Matt Mackall and many others',
731 author_email='mercurial@mercurial-scm.org',
741 author_email='mercurial@mercurial-scm.org',
732 url='https://mercurial-scm.org/',
742 url='https://mercurial-scm.org/',
733 download_url='https://mercurial-scm.org/release/',
743 download_url='https://mercurial-scm.org/release/',
734 description=('Fast scalable distributed SCM (revision control, version '
744 description=('Fast scalable distributed SCM (revision control, version '
735 'control) system'),
745 'control) system'),
736 long_description=('Mercurial is a distributed SCM tool written in Python.'
746 long_description=('Mercurial is a distributed SCM tool written in Python.'
737 ' It is used by a number of large projects that require'
747 ' It is used by a number of large projects that require'
738 ' fast, reliable distributed revision control, such as '
748 ' fast, reliable distributed revision control, such as '
739 'Mozilla.'),
749 'Mozilla.'),
740 license='GNU GPLv2 or any later version',
750 license='GNU GPLv2 or any later version',
741 classifiers=[
751 classifiers=[
742 'Development Status :: 6 - Mature',
752 'Development Status :: 6 - Mature',
743 'Environment :: Console',
753 'Environment :: Console',
744 'Intended Audience :: Developers',
754 'Intended Audience :: Developers',
745 'Intended Audience :: System Administrators',
755 'Intended Audience :: System Administrators',
746 'License :: OSI Approved :: GNU General Public License (GPL)',
756 'License :: OSI Approved :: GNU General Public License (GPL)',
747 'Natural Language :: Danish',
757 'Natural Language :: Danish',
748 'Natural Language :: English',
758 'Natural Language :: English',
749 'Natural Language :: German',
759 'Natural Language :: German',
750 'Natural Language :: Italian',
760 'Natural Language :: Italian',
751 'Natural Language :: Japanese',
761 'Natural Language :: Japanese',
752 'Natural Language :: Portuguese (Brazilian)',
762 'Natural Language :: Portuguese (Brazilian)',
753 'Operating System :: Microsoft :: Windows',
763 'Operating System :: Microsoft :: Windows',
754 'Operating System :: OS Independent',
764 'Operating System :: OS Independent',
755 'Operating System :: POSIX',
765 'Operating System :: POSIX',
756 'Programming Language :: C',
766 'Programming Language :: C',
757 'Programming Language :: Python',
767 'Programming Language :: Python',
758 'Topic :: Software Development :: Version Control',
768 'Topic :: Software Development :: Version Control',
759 ],
769 ],
760 scripts=scripts,
770 scripts=scripts,
761 packages=packages,
771 packages=packages,
762 ext_modules=extmodules,
772 ext_modules=extmodules,
763 data_files=datafiles,
773 data_files=datafiles,
764 package_data=packagedata,
774 package_data=packagedata,
765 cmdclass=cmdclass,
775 cmdclass=cmdclass,
766 distclass=hgdist,
776 distclass=hgdist,
767 options={'py2exe': {'packages': ['hgext', 'email']},
777 options={'py2exe': {'packages': ['hgext', 'email']},
768 'bdist_mpkg': {'zipdist': False,
778 'bdist_mpkg': {'zipdist': False,
769 'license': 'COPYING',
779 'license': 'COPYING',
770 'readme': 'contrib/macosx/Readme.html',
780 'readme': 'contrib/macosx/Readme.html',
771 'welcome': 'contrib/macosx/Welcome.html',
781 'welcome': 'contrib/macosx/Welcome.html',
772 },
782 },
773 },
783 },
774 **extra)
784 **extra)
General Comments 0
You need to be logged in to leave comments. Login now