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