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