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