changeset 43076 | 2372284d9457 |
parent 43044 | f9d35f01b8b3 |
child 43349 | c3e10f705a6c |
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
15 # codecs.escape_encode() where it raises SystemError on empty bytestring |
15 # codecs.escape_encode() where it raises SystemError on empty bytestring |
16 # bug link: https://bugs.python.org/issue25270 |
16 # bug link: https://bugs.python.org/issue25270 |
17 # |
17 # |
18 # TODO: when we actually work on Python 3, use this string as the |
18 # TODO: when we actually work on Python 3, use this string as the |
19 # actual supportedpy string. |
19 # actual supportedpy string. |
20 supportedpy = ','.join([ |
20 supportedpy = ','.join( |
21 '>=2.7', |
21 [ |
22 '!=3.0.*', |
22 '>=2.7', |
23 '!=3.1.*', |
23 '!=3.0.*', |
24 '!=3.2.*', |
24 '!=3.1.*', |
25 '!=3.3.*', |
25 '!=3.2.*', |
26 '!=3.4.*', |
26 '!=3.3.*', |
27 '!=3.5.0', |
27 '!=3.4.*', |
28 '!=3.5.1', |
28 '!=3.5.0', |
29 '!=3.5.2', |
29 '!=3.5.1', |
30 '!=3.6.0', |
30 '!=3.5.2', |
31 '!=3.6.1', |
31 '!=3.6.0', |
32 ]) |
32 '!=3.6.1', |
33 ] |
|
34 ) |
|
33 |
35 |
34 import sys, platform |
36 import sys, platform |
35 import sysconfig |
37 import sysconfig |
38 |
|
36 if sys.version_info[0] >= 3: |
39 if sys.version_info[0] >= 3: |
37 printf = eval('print') |
40 printf = eval('print') |
38 libdir_escape = 'unicode_escape' |
41 libdir_escape = 'unicode_escape' |
42 |
|
39 def sysstr(s): |
43 def sysstr(s): |
40 return s.decode('latin-1') |
44 return s.decode('latin-1') |
45 |
|
46 |
|
41 else: |
47 else: |
42 libdir_escape = 'string_escape' |
48 libdir_escape = 'string_escape' |
49 |
|
43 def printf(*args, **kwargs): |
50 def printf(*args, **kwargs): |
44 f = kwargs.get('file', sys.stdout) |
51 f = kwargs.get('file', sys.stdout) |
45 end = kwargs.get('end', '\n') |
52 end = kwargs.get('end', '\n') |
46 f.write(b' '.join(args) + end) |
53 f.write(b' '.join(args) + end) |
54 |
|
47 def sysstr(s): |
55 def sysstr(s): |
48 return s |
56 return s |
57 |
|
49 |
58 |
50 # Attempt to guide users to a modern pip - this means that 2.6 users |
59 # Attempt to guide users to a modern pip - this means that 2.6 users |
51 # should have a chance of getting a 4.2 release, and when we ratchet |
60 # should have a chance of getting a 4.2 release, and when we ratchet |
52 # the version requirement forward again hopefully everyone will get |
61 # the version requirement forward again hopefully everyone will get |
53 # something that works for them. |
62 # something that works for them. |
54 if sys.version_info < (2, 7, 0, 'final'): |
63 if sys.version_info < (2, 7, 0, 'final'): |
55 pip_message = ('This may be due to an out of date pip. ' |
64 pip_message = ( |
56 'Make sure you have pip >= 9.0.1.') |
65 'This may be due to an out of date pip. ' |
66 'Make sure you have pip >= 9.0.1.' |
|
67 ) |
|
57 try: |
68 try: |
58 import pip |
69 import pip |
70 |
|
59 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]]) |
71 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]]) |
60 if pip_version < (9, 0, 1) : |
72 if pip_version < (9, 0, 1): |
61 pip_message = ( |
73 pip_message = ( |
62 'Your pip version is out of date, please install ' |
74 'Your pip version is out of date, please install ' |
63 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__)) |
75 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__) |
76 ) |
|
64 else: |
77 else: |
65 # pip is new enough - it must be something else |
78 # pip is new enough - it must be something else |
66 pip_message = '' |
79 pip_message = '' |
67 except Exception: |
80 except Exception: |
68 pass |
81 pass |
69 error = """ |
82 error = """ |
70 Mercurial does not support Python older than 2.7. |
83 Mercurial does not support Python older than 2.7. |
71 Python {py} detected. |
84 Python {py} detected. |
72 {pip} |
85 {pip} |
73 """.format(py=sys.version_info, pip=pip_message) |
86 """.format( |
87 py=sys.version_info, pip=pip_message |
|
88 ) |
|
74 printf(error, file=sys.stderr) |
89 printf(error, file=sys.stderr) |
75 sys.exit(1) |
90 sys.exit(1) |
76 |
91 |
77 # We don't yet officially support Python 3. But we want to allow developers to |
92 # We don't yet officially support Python 3. But we want to allow developers to |
78 # hack on. Detect and disallow running on Python 3 by default. But provide a |
93 # hack on. Detect and disallow running on Python 3 by default. But provide a |
98 this command. No special environment variables or configuration changes are |
113 this command. No special environment variables or configuration changes are |
99 necessary to run `hg` with Python 3. |
114 necessary to run `hg` with Python 3. |
100 |
115 |
101 See https://www.mercurial-scm.org/wiki/Python3 for more on Mercurial's |
116 See https://www.mercurial-scm.org/wiki/Python3 for more on Mercurial's |
102 Python 3 support. |
117 Python 3 support. |
103 """.format(py='.'.join('%d' % x for x in sys.version_info[0:2])) |
118 """.format( |
119 py='.'.join('%d' % x for x in sys.version_info[0:2]) |
|
120 ) |
|
104 |
121 |
105 printf(error, file=sys.stderr) |
122 printf(error, file=sys.stderr) |
106 sys.exit(1) |
123 sys.exit(1) |
107 |
124 |
108 if sys.version_info[0] >= 3: |
125 if sys.version_info[0] >= 3: |
112 DYLIB_SUFFIX = sysconfig.get_config_vars()['SO'] |
129 DYLIB_SUFFIX = sysconfig.get_config_vars()['SO'] |
113 |
130 |
114 # Solaris Python packaging brain damage |
131 # Solaris Python packaging brain damage |
115 try: |
132 try: |
116 import hashlib |
133 import hashlib |
134 |
|
117 sha = hashlib.sha1() |
135 sha = hashlib.sha1() |
118 except ImportError: |
136 except ImportError: |
119 try: |
137 try: |
120 import sha |
138 import sha |
121 sha.sha # silence unused import warning |
139 |
140 sha.sha # silence unused import warning |
|
122 except ImportError: |
141 except ImportError: |
123 raise SystemExit( |
142 raise SystemExit( |
124 "Couldn't import standard hashlib (incomplete Python install).") |
143 "Couldn't import standard hashlib (incomplete Python install)." |
144 ) |
|
125 |
145 |
126 try: |
146 try: |
127 import zlib |
147 import zlib |
128 zlib.compressobj # silence unused import warning |
148 |
149 zlib.compressobj # silence unused import warning |
|
129 except ImportError: |
150 except ImportError: |
130 raise SystemExit( |
151 raise SystemExit( |
131 "Couldn't import standard zlib (incomplete Python install).") |
152 "Couldn't import standard zlib (incomplete Python install)." |
153 ) |
|
132 |
154 |
133 # The base IronPython distribution (as of 2.7.1) doesn't support bz2 |
155 # The base IronPython distribution (as of 2.7.1) doesn't support bz2 |
134 isironpython = False |
156 isironpython = False |
135 try: |
157 try: |
136 isironpython = (platform.python_implementation() |
158 isironpython = ( |
137 .lower().find("ironpython") != -1) |
159 platform.python_implementation().lower().find("ironpython") != -1 |
160 ) |
|
138 except AttributeError: |
161 except AttributeError: |
139 pass |
162 pass |
140 |
163 |
141 if isironpython: |
164 if isironpython: |
142 sys.stderr.write("warning: IronPython detected (no bz2 support)\n") |
165 sys.stderr.write("warning: IronPython detected (no bz2 support)\n") |
143 else: |
166 else: |
144 try: |
167 try: |
145 import bz2 |
168 import bz2 |
146 bz2.BZ2Compressor # silence unused import warning |
169 |
170 bz2.BZ2Compressor # silence unused import warning |
|
147 except ImportError: |
171 except ImportError: |
148 raise SystemExit( |
172 raise SystemExit( |
149 "Couldn't import standard bz2 (incomplete Python install).") |
173 "Couldn't import standard bz2 (incomplete Python install)." |
174 ) |
|
150 |
175 |
151 ispypy = "PyPy" in sys.version |
176 ispypy = "PyPy" in sys.version |
152 |
177 |
153 hgrustext = os.environ.get('HGWITHRUSTEXT') |
178 hgrustext = os.environ.get('HGWITHRUSTEXT') |
154 # TODO record it for proper rebuild upon changes |
179 # TODO record it for proper rebuild upon changes |
161 import stat, subprocess, time |
186 import stat, subprocess, time |
162 import re |
187 import re |
163 import shutil |
188 import shutil |
164 import tempfile |
189 import tempfile |
165 from distutils import log |
190 from distutils import log |
191 |
|
166 # We have issues with setuptools on some platforms and builders. Until |
192 # We have issues with setuptools on some platforms and builders. Until |
167 # those are resolved, setuptools is opt-in except for platforms where |
193 # those are resolved, setuptools is opt-in except for platforms where |
168 # we don't have issues. |
194 # we don't have issues. |
169 issetuptools = (os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ) |
195 issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ |
170 if issetuptools: |
196 if issetuptools: |
171 from setuptools import setup |
197 from setuptools import setup |
172 else: |
198 else: |
173 from distutils.core import setup |
199 from distutils.core import setup |
174 from distutils.ccompiler import new_compiler |
200 from distutils.ccompiler import new_compiler |
192 from distutils.version import StrictVersion |
218 from distutils.version import StrictVersion |
193 |
219 |
194 # Explain to distutils.StrictVersion how our release candidates are versionned |
220 # Explain to distutils.StrictVersion how our release candidates are versionned |
195 StrictVersion.version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?-?(rc(\d+))?$') |
221 StrictVersion.version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?-?(rc(\d+))?$') |
196 |
222 |
223 |
|
197 def write_if_changed(path, content): |
224 def write_if_changed(path, content): |
198 """Write content to a file iff the content hasn't changed.""" |
225 """Write content to a file iff the content hasn't changed.""" |
199 if os.path.exists(path): |
226 if os.path.exists(path): |
200 with open(path, 'rb') as fh: |
227 with open(path, 'rb') as fh: |
201 current = fh.read() |
228 current = fh.read() |
204 |
231 |
205 if current != content: |
232 if current != content: |
206 with open(path, 'wb') as fh: |
233 with open(path, 'wb') as fh: |
207 fh.write(content) |
234 fh.write(content) |
208 |
235 |
236 |
|
209 scripts = ['hg'] |
237 scripts = ['hg'] |
210 if os.name == 'nt': |
238 if os.name == 'nt': |
211 # We remove hg.bat if we are able to build hg.exe. |
239 # We remove hg.bat if we are able to build hg.exe. |
212 scripts.append('contrib/win32/hg.bat') |
240 scripts.append('contrib/win32/hg.bat') |
241 |
|
213 |
242 |
214 def cancompile(cc, code): |
243 def cancompile(cc, code): |
215 tmpdir = tempfile.mkdtemp(prefix='hg-install-') |
244 tmpdir = tempfile.mkdtemp(prefix='hg-install-') |
216 devnull = oldstderr = None |
245 devnull = oldstderr = None |
217 try: |
246 try: |
236 os.dup2(oldstderr, sys.stderr.fileno()) |
265 os.dup2(oldstderr, sys.stderr.fileno()) |
237 if devnull is not None: |
266 if devnull is not None: |
238 devnull.close() |
267 devnull.close() |
239 shutil.rmtree(tmpdir) |
268 shutil.rmtree(tmpdir) |
240 |
269 |
270 |
|
241 # simplified version of distutils.ccompiler.CCompiler.has_function |
271 # simplified version of distutils.ccompiler.CCompiler.has_function |
242 # that actually removes its temporary files. |
272 # that actually removes its temporary files. |
243 def hasfunction(cc, funcname): |
273 def hasfunction(cc, funcname): |
244 code = 'int main(void) { %s(); }\n' % funcname |
274 code = 'int main(void) { %s(); }\n' % funcname |
245 return cancompile(cc, code) |
275 return cancompile(cc, code) |
246 |
276 |
277 |
|
247 def hasheader(cc, headername): |
278 def hasheader(cc, headername): |
248 code = '#include <%s>\nint main(void) { return 0; }\n' % headername |
279 code = '#include <%s>\nint main(void) { return 0; }\n' % headername |
249 return cancompile(cc, code) |
280 return cancompile(cc, code) |
250 |
281 |
282 |
|
251 # py2exe needs to be installed to work |
283 # py2exe needs to be installed to work |
252 try: |
284 try: |
253 import py2exe |
285 import py2exe |
254 py2exe.Distribution # silence unused import warning |
286 |
287 py2exe.Distribution # silence unused import warning |
|
255 py2exeloaded = True |
288 py2exeloaded = True |
256 # import py2exe's patched Distribution class |
289 # import py2exe's patched Distribution class |
257 from distutils.core import Distribution |
290 from distutils.core import Distribution |
258 except ImportError: |
291 except ImportError: |
259 py2exeloaded = False |
292 py2exeloaded = False |
260 |
293 |
294 |
|
261 def runcmd(cmd, env, cwd=None): |
295 def runcmd(cmd, env, cwd=None): |
262 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, |
296 p = subprocess.Popen( |
263 stderr=subprocess.PIPE, env=env, cwd=cwd) |
297 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd |
298 ) |
|
264 out, err = p.communicate() |
299 out, err = p.communicate() |
265 return p.returncode, out, err |
300 return p.returncode, out, err |
301 |
|
266 |
302 |
267 class hgcommand(object): |
303 class hgcommand(object): |
268 def __init__(self, cmd, env): |
304 def __init__(self, cmd, env): |
269 self.cmd = cmd |
305 self.cmd = cmd |
270 self.env = env |
306 self.env = env |
277 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr) |
313 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr) |
278 printf(err, file=sys.stderr) |
314 printf(err, file=sys.stderr) |
279 return '' |
315 return '' |
280 return out |
316 return out |
281 |
317 |
318 |
|
282 def filterhgerr(err): |
319 def filterhgerr(err): |
283 # If root is executing setup.py, but the repository is owned by |
320 # If root is executing setup.py, but the repository is owned by |
284 # another user (as in "sudo python setup.py install") we will get |
321 # another user (as in "sudo python setup.py install") we will get |
285 # trust warnings since the .hg/hgrc file is untrusted. That is |
322 # trust warnings since the .hg/hgrc file is untrusted. That is |
286 # fine, we don't want to load it anyway. Python may warn about |
323 # fine, we don't want to load it anyway. Python may warn about |
287 # a missing __init__.py in mercurial/locale, we also ignore that. |
324 # a missing __init__.py in mercurial/locale, we also ignore that. |
288 err = [e for e in err.splitlines() |
325 err = [ |
289 if (not e.startswith(b'not trusting file') |
326 e |
290 and not e.startswith(b'warning: Not importing') |
327 for e in err.splitlines() |
291 and not e.startswith(b'obsolete feature not enabled') |
328 if ( |
292 and not e.startswith(b'*** failed to import extension') |
329 not e.startswith(b'not trusting file') |
293 and not e.startswith(b'devel-warn:') |
330 and not e.startswith(b'warning: Not importing') |
294 and not (e.startswith(b'(third party extension') |
331 and not e.startswith(b'obsolete feature not enabled') |
295 and e.endswith(b'or newer of Mercurial; disabling)')))] |
332 and not e.startswith(b'*** failed to import extension') |
333 and not e.startswith(b'devel-warn:') |
|
334 and not ( |
|
335 e.startswith(b'(third party extension') |
|
336 and e.endswith(b'or newer of Mercurial; disabling)') |
|
337 ) |
|
338 ) |
|
339 ] |
|
296 return b'\n'.join(b' ' + e for e in err) |
340 return b'\n'.join(b' ' + e for e in err) |
341 |
|
297 |
342 |
298 def findhg(): |
343 def findhg(): |
299 """Try to figure out how we should invoke hg for examining the local |
344 """Try to figure out how we should invoke hg for examining the local |
300 repository contents. |
345 repository contents. |
301 |
346 |
332 except EnvironmentError: |
377 except EnvironmentError: |
333 retcode = -1 |
378 retcode = -1 |
334 if retcode == 0 and not filterhgerr(err): |
379 if retcode == 0 and not filterhgerr(err): |
335 return hgcommand(hgcmd, hgenv) |
380 return hgcommand(hgcmd, hgenv) |
336 |
381 |
337 raise SystemExit('Unable to find a working hg binary to extract the ' |
382 raise SystemExit( |
338 'version from the repository tags') |
383 'Unable to find a working hg binary to extract the ' |
384 'version from the repository tags' |
|
385 ) |
|
386 |
|
339 |
387 |
340 def localhgenv(): |
388 def localhgenv(): |
341 """Get an environment dictionary to use for invoking or importing |
389 """Get an environment dictionary to use for invoking or importing |
342 mercurial from the local repository.""" |
390 mercurial from the local repository.""" |
343 # Execute hg out of this directory with a custom environment which takes |
391 # Execute hg out of this directory with a custom environment which takes |
344 # care to not use any hgrc files and do no localization. |
392 # care to not use any hgrc files and do no localization. |
345 env = {'HGMODULEPOLICY': 'py', |
393 env = { |
346 'HGRCPATH': '', |
394 'HGMODULEPOLICY': 'py', |
347 'LANGUAGE': 'C', |
395 'HGRCPATH': '', |
348 'PATH': ''} # make pypi modules that use os.environ['PATH'] happy |
396 'LANGUAGE': 'C', |
397 'PATH': '', |
|
398 } # make pypi modules that use os.environ['PATH'] happy |
|
349 if 'LD_LIBRARY_PATH' in os.environ: |
399 if 'LD_LIBRARY_PATH' in os.environ: |
350 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] |
400 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] |
351 if 'SystemRoot' in os.environ: |
401 if 'SystemRoot' in os.environ: |
352 # SystemRoot is required by Windows to load various DLLs. See: |
402 # SystemRoot is required by Windows to load various DLLs. See: |
353 # https://bugs.python.org/issue13524#msg148850 |
403 # https://bugs.python.org/issue13524#msg148850 |
354 env['SystemRoot'] = os.environ['SystemRoot'] |
404 env['SystemRoot'] = os.environ['SystemRoot'] |
355 return env |
405 return env |
406 |
|
356 |
407 |
357 version = '' |
408 version = '' |
358 |
409 |
359 if os.path.isdir('.hg'): |
410 if os.path.isdir('.hg'): |
360 hg = findhg() |
411 hg = findhg() |
365 # Bail out if hg is having problems interacting with this repository, |
416 # Bail out if hg is having problems interacting with this repository, |
366 # rather than falling through and producing a bogus version number. |
417 # rather than falling through and producing a bogus version number. |
367 # Continuing with an invalid version number will break extensions |
418 # Continuing with an invalid version number will break extensions |
368 # that define minimumhgversion. |
419 # that define minimumhgversion. |
369 raise SystemExit('Unable to determine hg version from local repository') |
420 raise SystemExit('Unable to determine hg version from local repository') |
370 if numerictags: # tag(s) found |
421 if numerictags: # tag(s) found |
371 version = numerictags[-1] |
422 version = numerictags[-1] |
372 if hgid.endswith('+'): # propagate the dirty status to the tag |
423 if hgid.endswith('+'): # propagate the dirty status to the tag |
373 version += '+' |
424 version += '+' |
374 else: # no tag found |
425 else: # no tag found |
375 ltagcmd = ['parents', '--template', '{latesttag}'] |
426 ltagcmd = ['parents', '--template', '{latesttag}'] |
376 ltag = sysstr(hg.run(ltagcmd)) |
427 ltag = sysstr(hg.run(ltagcmd)) |
377 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag] |
428 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag] |
378 changessince = len(hg.run(changessincecmd).splitlines()) |
429 changessince = len(hg.run(changessincecmd).splitlines()) |
379 version = '%s+%s-%s' % (ltag, changessince, hgid) |
430 version = '%s+%s-%s' % (ltag, changessince, hgid) |
380 if version.endswith('+'): |
431 if version.endswith('+'): |
381 version += time.strftime('%Y%m%d') |
432 version += time.strftime('%Y%m%d') |
382 elif os.path.exists('.hg_archival.txt'): |
433 elif os.path.exists('.hg_archival.txt'): |
383 kw = dict([[t.strip() for t in l.split(':', 1)] |
434 kw = dict( |
384 for l in open('.hg_archival.txt')]) |
435 [[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')] |
436 ) |
|
385 if 'tag' in kw: |
437 if 'tag' in kw: |
386 version = kw['tag'] |
438 version = kw['tag'] |
387 elif 'latesttag' in kw: |
439 elif 'latesttag' in kw: |
388 if 'changessincelatesttag' in kw: |
440 if 'changessincelatesttag' in kw: |
389 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw |
441 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw |
395 if version: |
447 if version: |
396 versionb = version |
448 versionb = version |
397 if not isinstance(versionb, bytes): |
449 if not isinstance(versionb, bytes): |
398 versionb = versionb.encode('ascii') |
450 versionb = versionb.encode('ascii') |
399 |
451 |
400 write_if_changed('mercurial/__version__.py', b''.join([ |
452 write_if_changed( |
401 b'# this file is autogenerated by setup.py\n' |
453 'mercurial/__version__.py', |
402 b'version = b"%s"\n' % versionb, |
454 b''.join( |
403 ])) |
455 [ |
456 b'# this file is autogenerated by setup.py\n' |
|
457 b'version = b"%s"\n' % versionb, |
|
458 ] |
|
459 ), |
|
460 ) |
|
404 |
461 |
405 try: |
462 try: |
406 oldpolicy = os.environ.get('HGMODULEPOLICY', None) |
463 oldpolicy = os.environ.get('HGMODULEPOLICY', None) |
407 os.environ['HGMODULEPOLICY'] = 'py' |
464 os.environ['HGMODULEPOLICY'] = 'py' |
408 from mercurial import __version__ |
465 from mercurial import __version__ |
466 |
|
409 version = __version__.version |
467 version = __version__.version |
410 except ImportError: |
468 except ImportError: |
411 version = b'unknown' |
469 version = b'unknown' |
412 finally: |
470 finally: |
413 if oldpolicy is None: |
471 if oldpolicy is None: |
414 del os.environ['HGMODULEPOLICY'] |
472 del os.environ['HGMODULEPOLICY'] |
415 else: |
473 else: |
416 os.environ['HGMODULEPOLICY'] = oldpolicy |
474 os.environ['HGMODULEPOLICY'] = oldpolicy |
417 |
475 |
476 |
|
418 class hgbuild(build): |
477 class hgbuild(build): |
419 # Insert hgbuildmo first so that files in mercurial/locale/ are found |
478 # Insert hgbuildmo first so that files in mercurial/locale/ are found |
420 # when build_py is run next. |
479 # when build_py is run next. |
421 sub_commands = [('build_mo', None)] + build.sub_commands |
480 sub_commands = [('build_mo', None)] + build.sub_commands |
422 |
481 |
482 |
|
423 class hgbuildmo(build): |
483 class hgbuildmo(build): |
424 |
484 |
425 description = "build translations (.mo files)" |
485 description = "build translations (.mo files)" |
426 |
486 |
427 def run(self): |
487 def run(self): |
428 if not find_executable('msgfmt'): |
488 if not find_executable('msgfmt'): |
429 self.warn("could not find msgfmt executable, no translations " |
489 self.warn( |
430 "will be built") |
490 "could not find msgfmt executable, no translations " |
491 "will be built" |
|
492 ) |
|
431 return |
493 return |
432 |
494 |
433 podir = 'i18n' |
495 podir = 'i18n' |
434 if not os.path.isdir(podir): |
496 if not os.path.isdir(podir): |
435 self.warn("could not find %s/ directory" % podir) |
497 self.warn("could not find %s/ directory" % podir) |
464 def has_ext_modules(self): |
526 def has_ext_modules(self): |
465 # self.ext_modules is emptied in hgbuildpy.finalize_options which is |
527 # self.ext_modules is emptied in hgbuildpy.finalize_options which is |
466 # too late for some cases |
528 # too late for some cases |
467 return not self.pure and Distribution.has_ext_modules(self) |
529 return not self.pure and Distribution.has_ext_modules(self) |
468 |
530 |
531 |
|
469 # This is ugly as a one-liner. So use a variable. |
532 # This is ugly as a one-liner. So use a variable. |
470 buildextnegops = dict(getattr(build_ext, 'negative_options', {})) |
533 buildextnegops = dict(getattr(build_ext, 'negative_options', {})) |
471 buildextnegops['no-zstd'] = 'zstd' |
534 buildextnegops['no-zstd'] = 'zstd' |
472 buildextnegops['no-rust'] = 'rust' |
535 buildextnegops['no-rust'] = 'rust' |
473 |
536 |
537 |
|
474 class hgbuildext(build_ext): |
538 class hgbuildext(build_ext): |
475 user_options = build_ext.user_options + [ |
539 user_options = build_ext.user_options + [ |
476 ('zstd', None, 'compile zstd bindings [default]'), |
540 ('zstd', None, 'compile zstd bindings [default]'), |
477 ('no-zstd', None, 'do not compile zstd bindings'), |
541 ('no-zstd', None, 'do not compile zstd bindings'), |
478 ('rust', None, |
542 ( |
479 'compile Rust extensions if they are in use ' |
543 'rust', |
480 '(requires Cargo) [default]'), |
544 None, |
545 'compile Rust extensions if they are in use ' |
|
546 '(requires Cargo) [default]', |
|
547 ), |
|
481 ('no-rust', None, 'do not compile Rust extensions'), |
548 ('no-rust', None, 'do not compile Rust extensions'), |
482 ] |
549 ] |
483 |
550 |
484 boolean_options = build_ext.boolean_options + ['zstd', 'rust'] |
551 boolean_options = build_ext.boolean_options + ['zstd', 'rust'] |
485 negative_opt = buildextnegops |
552 negative_opt = buildextnegops |
497 self.parallel = True |
564 self.parallel = True |
498 |
565 |
499 return build_ext.finalize_options(self) |
566 return build_ext.finalize_options(self) |
500 |
567 |
501 def build_extensions(self): |
568 def build_extensions(self): |
502 ruststandalones = [e for e in self.extensions |
569 ruststandalones = [ |
503 if isinstance(e, RustStandaloneExtension)] |
570 e for e in self.extensions if isinstance(e, RustStandaloneExtension) |
504 self.extensions = [e for e in self.extensions |
571 ] |
505 if e not in ruststandalones] |
572 self.extensions = [ |
573 e for e in self.extensions if e not in ruststandalones |
|
574 ] |
|
506 # Filter out zstd if disabled via argument. |
575 # Filter out zstd if disabled via argument. |
507 if not self.zstd: |
576 if not self.zstd: |
508 self.extensions = [e for e in self.extensions |
577 self.extensions = [ |
509 if e.name != 'mercurial.zstd'] |
578 e for e in self.extensions if e.name != 'mercurial.zstd' |
579 ] |
|
510 |
580 |
511 # Build Rust standalon extensions if it'll be used |
581 # Build Rust standalon extensions if it'll be used |
512 # and its build is not explictely disabled (for external build |
582 # and its build is not explictely disabled (for external build |
513 # as Linux distributions would do) |
583 # as Linux distributions would do) |
514 if self.distribution.rust and self.rust and hgrustext != 'direct-ffi': |
584 if self.distribution.rust and self.rust and hgrustext != 'direct-ffi': |
516 rustext.build('' if self.inplace else self.build_lib) |
586 rustext.build('' if self.inplace else self.build_lib) |
517 |
587 |
518 return build_ext.build_extensions(self) |
588 return build_ext.build_extensions(self) |
519 |
589 |
520 def build_extension(self, ext): |
590 def build_extension(self, ext): |
521 if (self.distribution.rust and self.rust |
591 if ( |
522 and isinstance(ext, RustExtension)): |
592 self.distribution.rust |
523 ext.rustbuild() |
593 and self.rust |
594 and isinstance(ext, RustExtension) |
|
595 ): |
|
596 ext.rustbuild() |
|
524 try: |
597 try: |
525 build_ext.build_extension(self, ext) |
598 build_ext.build_extension(self, ext) |
526 except CCompilerError: |
599 except CCompilerError: |
527 if not getattr(ext, 'optional', False): |
600 if not getattr(ext, 'optional', False): |
528 raise |
601 raise |
529 log.warn("Failed to build optional extension '%s' (skipping)", |
602 log.warn( |
530 ext.name) |
603 "Failed to build optional extension '%s' (skipping)", ext.name |
604 ) |
|
605 |
|
531 |
606 |
532 class hgbuildscripts(build_scripts): |
607 class hgbuildscripts(build_scripts): |
533 def run(self): |
608 def run(self): |
534 if os.name != 'nt' or self.distribution.pure: |
609 if os.name != 'nt' or self.distribution.pure: |
535 return build_scripts.run(self) |
610 return build_scripts.run(self) |
552 # Remove hg.bat because it is redundant with hg.exe. |
627 # Remove hg.bat because it is redundant with hg.exe. |
553 self.scripts.remove('contrib/win32/hg.bat') |
628 self.scripts.remove('contrib/win32/hg.bat') |
554 |
629 |
555 return build_scripts.run(self) |
630 return build_scripts.run(self) |
556 |
631 |
632 |
|
557 class hgbuildpy(build_py): |
633 class hgbuildpy(build_py): |
558 def finalize_options(self): |
634 def finalize_options(self): |
559 build_py.finalize_options(self) |
635 build_py.finalize_options(self) |
560 |
636 |
561 if self.distribution.pure: |
637 if self.distribution.pure: |
563 elif self.distribution.cffi: |
639 elif self.distribution.cffi: |
564 from mercurial.cffi import ( |
640 from mercurial.cffi import ( |
565 bdiffbuild, |
641 bdiffbuild, |
566 mpatchbuild, |
642 mpatchbuild, |
567 ) |
643 ) |
568 exts = [mpatchbuild.ffi.distutils_extension(), |
644 |
569 bdiffbuild.ffi.distutils_extension()] |
645 exts = [ |
646 mpatchbuild.ffi.distutils_extension(), |
|
647 bdiffbuild.ffi.distutils_extension(), |
|
648 ] |
|
570 # cffi modules go here |
649 # cffi modules go here |
571 if sys.platform == 'darwin': |
650 if sys.platform == 'darwin': |
572 from mercurial.cffi import osutilbuild |
651 from mercurial.cffi import osutilbuild |
652 |
|
573 exts.append(osutilbuild.ffi.distutils_extension()) |
653 exts.append(osutilbuild.ffi.distutils_extension()) |
574 self.distribution.ext_modules = exts |
654 self.distribution.ext_modules = exts |
575 else: |
655 else: |
576 h = os.path.join(get_python_inc(), 'Python.h') |
656 h = os.path.join(get_python_inc(), 'Python.h') |
577 if not os.path.exists(h): |
657 if not os.path.exists(h): |
578 raise SystemExit('Python headers are required to build ' |
658 raise SystemExit( |
579 'Mercurial but weren\'t found in %s' % h) |
659 'Python headers are required to build ' |
660 'Mercurial but weren\'t found in %s' % h |
|
661 ) |
|
580 |
662 |
581 def run(self): |
663 def run(self): |
582 basepath = os.path.join(self.build_lib, 'mercurial') |
664 basepath = os.path.join(self.build_lib, 'mercurial') |
583 self.mkpath(basepath) |
665 self.mkpath(basepath) |
584 |
666 |
589 # in-place build should run without rebuilding and Rust extensions |
671 # in-place build should run without rebuilding and Rust extensions |
590 modulepolicy = 'rust+c-allow' if rust else 'allow' |
672 modulepolicy = 'rust+c-allow' if rust else 'allow' |
591 else: |
673 else: |
592 modulepolicy = 'rust+c' if rust else 'c' |
674 modulepolicy = 'rust+c' if rust else 'c' |
593 |
675 |
594 content = b''.join([ |
676 content = b''.join( |
595 b'# this file is autogenerated by setup.py\n', |
677 [ |
596 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'), |
678 b'# this file is autogenerated by setup.py\n', |
597 ]) |
679 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'), |
598 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), |
680 ] |
599 content) |
681 ) |
682 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content) |
|
600 |
683 |
601 build_py.run(self) |
684 build_py.run(self) |
685 |
|
602 |
686 |
603 class buildhgextindex(Command): |
687 class buildhgextindex(Command): |
604 description = 'generate prebuilt index of hgext (for frozen package)' |
688 description = 'generate prebuilt index of hgext (for frozen package)' |
605 user_options = [] |
689 user_options = [] |
606 _indexfilename = 'hgext/__index__.py' |
690 _indexfilename = 'hgext/__index__.py' |
615 if os.path.exists(self._indexfilename): |
699 if os.path.exists(self._indexfilename): |
616 with open(self._indexfilename, 'w') as f: |
700 with open(self._indexfilename, 'w') as f: |
617 f.write('# empty\n') |
701 f.write('# empty\n') |
618 |
702 |
619 # here no extension enabled, disabled() lists up everything |
703 # here no extension enabled, disabled() lists up everything |
620 code = ('import pprint; from mercurial import extensions; ' |
704 code = ( |
621 'pprint.pprint(extensions.disabled())') |
705 'import pprint; from mercurial import extensions; ' |
622 returncode, out, err = runcmd([sys.executable, '-c', code], |
706 'pprint.pprint(extensions.disabled())' |
623 localhgenv()) |
707 ) |
708 returncode, out, err = runcmd( |
|
709 [sys.executable, '-c', code], localhgenv() |
|
710 ) |
|
624 if err or returncode != 0: |
711 if err or returncode != 0: |
625 raise DistutilsExecError(err) |
712 raise DistutilsExecError(err) |
626 |
713 |
627 with open(self._indexfilename, 'wb') as f: |
714 with open(self._indexfilename, 'wb') as f: |
628 f.write(b'# this file is autogenerated by setup.py\n') |
715 f.write(b'# this file is autogenerated by setup.py\n') |
629 f.write(b'docs = ') |
716 f.write(b'docs = ') |
630 f.write(out) |
717 f.write(out) |
631 |
718 |
719 |
|
632 class buildhgexe(build_ext): |
720 class buildhgexe(build_ext): |
633 description = 'compile hg.exe from mercurial/exewrapper.c' |
721 description = 'compile hg.exe from mercurial/exewrapper.c' |
634 user_options = build_ext.user_options + [ |
722 user_options = build_ext.user_options + [ |
635 ('long-paths-support', None, 'enable support for long paths on ' |
723 ( |
636 'Windows (off by default and ' |
724 'long-paths-support', |
637 'experimental)'), |
725 None, |
726 'enable support for long paths on ' |
|
727 'Windows (off by default and ' |
|
728 'experimental)', |
|
729 ), |
|
638 ] |
730 ] |
639 |
731 |
640 LONG_PATHS_MANIFEST = """ |
732 LONG_PATHS_MANIFEST = """ |
641 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
733 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
642 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
734 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
654 |
746 |
655 def build_extensions(self): |
747 def build_extensions(self): |
656 if os.name != 'nt': |
748 if os.name != 'nt': |
657 return |
749 return |
658 if isinstance(self.compiler, HackedMingw32CCompiler): |
750 if isinstance(self.compiler, HackedMingw32CCompiler): |
659 self.compiler.compiler_so = self.compiler.compiler # no -mdll |
751 self.compiler.compiler_so = self.compiler.compiler # no -mdll |
660 self.compiler.dll_libraries = [] # no -lmsrvc90 |
752 self.compiler.dll_libraries = [] # no -lmsrvc90 |
661 |
753 |
662 # Different Python installs can have different Python library |
754 # Different Python installs can have different Python library |
663 # names. e.g. the official CPython distribution uses pythonXY.dll |
755 # names. e.g. the official CPython distribution uses pythonXY.dll |
664 # and MinGW uses libpythonX.Y.dll. |
756 # and MinGW uses libpythonX.Y.dll. |
665 _kernel32 = ctypes.windll.kernel32 |
757 _kernel32 = ctypes.windll.kernel32 |
666 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p, |
758 _kernel32.GetModuleFileNameA.argtypes = [ |
667 ctypes.c_void_p, |
759 ctypes.c_void_p, |
668 ctypes.c_ulong] |
760 ctypes.c_void_p, |
761 ctypes.c_ulong, |
|
762 ] |
|
669 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong |
763 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong |
670 size = 1000 |
764 size = 1000 |
671 buf = ctypes.create_string_buffer(size + 1) |
765 buf = ctypes.create_string_buffer(size + 1) |
672 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf), |
766 filelen = _kernel32.GetModuleFileNameA( |
673 size) |
767 sys.dllhandle, ctypes.byref(buf), size |
768 ) |
|
674 |
769 |
675 if filelen > 0 and filelen != size: |
770 if filelen > 0 and filelen != size: |
676 dllbasename = os.path.basename(buf.value) |
771 dllbasename = os.path.basename(buf.value) |
677 if not dllbasename.lower().endswith(b'.dll'): |
772 if not dllbasename.lower().endswith(b'.dll'): |
678 raise SystemExit('Python DLL does not end with .dll: %s' % |
773 raise SystemExit( |
679 dllbasename) |
774 'Python DLL does not end with .dll: %s' % dllbasename |
775 ) |
|
680 pythonlib = dllbasename[:-4] |
776 pythonlib = dllbasename[:-4] |
681 else: |
777 else: |
682 log.warn('could not determine Python DLL filename; ' |
778 log.warn( |
683 'assuming pythonXY') |
779 'could not determine Python DLL filename; ' 'assuming pythonXY' |
780 ) |
|
684 |
781 |
685 hv = sys.hexversion |
782 hv = sys.hexversion |
686 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff) |
783 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF) |
687 |
784 |
688 log.info('using %s as Python library name' % pythonlib) |
785 log.info('using %s as Python library name' % pythonlib) |
689 with open('mercurial/hgpythonlib.h', 'wb') as f: |
786 with open('mercurial/hgpythonlib.h', 'wb') as f: |
690 f.write(b'/* this file is autogenerated by setup.py */\n') |
787 f.write(b'/* this file is autogenerated by setup.py */\n') |
691 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib) |
788 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib) |
692 |
789 |
693 macros = None |
790 macros = None |
694 if sys.version_info[0] >= 3: |
791 if sys.version_info[0] >= 3: |
695 macros = [('_UNICODE', None), ('UNICODE', None)] |
792 macros = [('_UNICODE', None), ('UNICODE', None)] |
696 |
793 |
697 objects = self.compiler.compile(['mercurial/exewrapper.c'], |
794 objects = self.compiler.compile( |
698 output_dir=self.build_temp, |
795 ['mercurial/exewrapper.c'], |
699 macros=macros) |
796 output_dir=self.build_temp, |
797 macros=macros, |
|
798 ) |
|
700 dir = os.path.dirname(self.get_ext_fullpath('dummy')) |
799 dir = os.path.dirname(self.get_ext_fullpath('dummy')) |
701 self.hgtarget = os.path.join(dir, 'hg') |
800 self.hgtarget = os.path.join(dir, 'hg') |
702 self.compiler.link_executable(objects, self.hgtarget, |
801 self.compiler.link_executable( |
703 libraries=[], |
802 objects, self.hgtarget, libraries=[], output_dir=self.build_temp |
704 output_dir=self.build_temp) |
803 ) |
705 if self.long_paths_support: |
804 if self.long_paths_support: |
706 self.addlongpathsmanifest() |
805 self.addlongpathsmanifest() |
707 |
806 |
708 def addlongpathsmanifest(self): |
807 def addlongpathsmanifest(self): |
709 r"""Add manifest pieces so that hg.exe understands long paths |
808 r"""Add manifest pieces so that hg.exe understands long paths |
731 inputresource = '-inputresource:%s;#1' % exefname |
830 inputresource = '-inputresource:%s;#1' % exefname |
732 outputresource = '-outputresource:%s;#1' % exefname |
831 outputresource = '-outputresource:%s;#1' % exefname |
733 log.info("running mt.exe to update hg.exe's manifest in-place") |
832 log.info("running mt.exe to update hg.exe's manifest in-place") |
734 # supplying both -manifest and -inputresource to mt.exe makes |
833 # supplying both -manifest and -inputresource to mt.exe makes |
735 # it merge the embedded and supplied manifests in the -outputresource |
834 # it merge the embedded and supplied manifests in the -outputresource |
736 self.spawn(['mt.exe', '-nologo', '-manifest', manfname, |
835 self.spawn( |
737 inputresource, outputresource]) |
836 [ |
837 'mt.exe', |
|
838 '-nologo', |
|
839 '-manifest', |
|
840 manfname, |
|
841 inputresource, |
|
842 outputresource, |
|
843 ] |
|
844 ) |
|
738 log.info("done updating hg.exe's manifest") |
845 log.info("done updating hg.exe's manifest") |
739 os.remove(manfname) |
846 os.remove(manfname) |
740 |
847 |
741 @property |
848 @property |
742 def hgexepath(self): |
849 def hgexepath(self): |
743 dir = os.path.dirname(self.get_ext_fullpath('dummy')) |
850 dir = os.path.dirname(self.get_ext_fullpath('dummy')) |
744 return os.path.join(self.build_temp, dir, 'hg.exe') |
851 return os.path.join(self.build_temp, dir, 'hg.exe') |
852 |
|
745 |
853 |
746 class hgbuilddoc(Command): |
854 class hgbuilddoc(Command): |
747 description = 'build documentation' |
855 description = 'build documentation' |
748 user_options = [ |
856 user_options = [ |
749 ('man', None, 'generate man pages'), |
857 ('man', None, 'generate man pages'), |
780 |
888 |
781 def gentxt(root): |
889 def gentxt(root): |
782 txt = 'doc/%s.txt' % root |
890 txt = 'doc/%s.txt' % root |
783 log.info('generating %s' % txt) |
891 log.info('generating %s' % txt) |
784 res, out, err = runcmd( |
892 res, out, err = runcmd( |
785 [sys.executable, 'gendoc.py', root], |
893 [sys.executable, 'gendoc.py', root], os.environ, cwd='doc' |
786 os.environ, |
894 ) |
787 cwd='doc') |
|
788 if res: |
895 if res: |
789 raise SystemExit('error running gendoc.py: %s' % |
896 raise SystemExit( |
790 '\n'.join([out, err])) |
897 'error running gendoc.py: %s' % '\n'.join([out, err]) |
898 ) |
|
791 |
899 |
792 with open(txt, 'wb') as fh: |
900 with open(txt, 'wb') as fh: |
793 fh.write(out) |
901 fh.write(out) |
794 |
902 |
795 def gengendoc(root): |
903 def gengendoc(root): |
797 |
905 |
798 log.info('generating %s' % gendoc) |
906 log.info('generating %s' % gendoc) |
799 res, out, err = runcmd( |
907 res, out, err = runcmd( |
800 [sys.executable, 'gendoc.py', '%s.gendoc' % root], |
908 [sys.executable, 'gendoc.py', '%s.gendoc' % root], |
801 os.environ, |
909 os.environ, |
802 cwd='doc') |
910 cwd='doc', |
911 ) |
|
803 if res: |
912 if res: |
804 raise SystemExit('error running gendoc: %s' % |
913 raise SystemExit( |
805 '\n'.join([out, err])) |
914 'error running gendoc: %s' % '\n'.join([out, err]) |
915 ) |
|
806 |
916 |
807 with open(gendoc, 'wb') as fh: |
917 with open(gendoc, 'wb') as fh: |
808 fh.write(out) |
918 fh.write(out) |
809 |
919 |
810 def genman(root): |
920 def genman(root): |
811 log.info('generating doc/%s' % root) |
921 log.info('generating doc/%s' % root) |
812 res, out, err = runcmd( |
922 res, out, err = runcmd( |
813 [sys.executable, 'runrst', 'hgmanpage', '--halt', 'warning', |
923 [ |
814 '--strip-elements-with-class', 'htmlonly', |
924 sys.executable, |
815 '%s.txt' % root, root], |
925 'runrst', |
926 'hgmanpage', |
|
927 '--halt', |
|
928 'warning', |
|
929 '--strip-elements-with-class', |
|
930 'htmlonly', |
|
931 '%s.txt' % root, |
|
932 root, |
|
933 ], |
|
816 os.environ, |
934 os.environ, |
817 cwd='doc') |
935 cwd='doc', |
936 ) |
|
818 if res: |
937 if res: |
819 raise SystemExit('error running runrst: %s' % |
938 raise SystemExit( |
820 '\n'.join([out, err])) |
939 'error running runrst: %s' % '\n'.join([out, err]) |
940 ) |
|
821 |
941 |
822 normalizecrlf('doc/%s' % root) |
942 normalizecrlf('doc/%s' % root) |
823 |
943 |
824 def genhtml(root): |
944 def genhtml(root): |
825 log.info('generating doc/%s.html' % root) |
945 log.info('generating doc/%s.html' % root) |
826 res, out, err = runcmd( |
946 res, out, err = runcmd( |
827 [sys.executable, 'runrst', 'html', '--halt', 'warning', |
947 [ |
828 '--link-stylesheet', '--stylesheet-path', 'style.css', |
948 sys.executable, |
829 '%s.txt' % root, '%s.html' % root], |
949 'runrst', |
950 'html', |
|
951 '--halt', |
|
952 'warning', |
|
953 '--link-stylesheet', |
|
954 '--stylesheet-path', |
|
955 'style.css', |
|
956 '%s.txt' % root, |
|
957 '%s.html' % root, |
|
958 ], |
|
830 os.environ, |
959 os.environ, |
831 cwd='doc') |
960 cwd='doc', |
961 ) |
|
832 if res: |
962 if res: |
833 raise SystemExit('error running runrst: %s' % |
963 raise SystemExit( |
834 '\n'.join([out, err])) |
964 'error running runrst: %s' % '\n'.join([out, err]) |
965 ) |
|
835 |
966 |
836 normalizecrlf('doc/%s.html' % root) |
967 normalizecrlf('doc/%s.html' % root) |
837 |
968 |
838 # This logic is duplicated in doc/Makefile. |
969 # This logic is duplicated in doc/Makefile. |
839 sources = set(f for f in os.listdir('mercurial/help') |
970 sources = set( |
840 if re.search(r'[0-9]\.txt$', f)) |
971 f |
972 for f in os.listdir('mercurial/help') |
|
973 if re.search(r'[0-9]\.txt$', f) |
|
974 ) |
|
841 |
975 |
842 # common.txt is a one-off. |
976 # common.txt is a one-off. |
843 gentxt('common') |
977 gentxt('common') |
844 |
978 |
845 for source in sorted(sources): |
979 for source in sorted(sources): |
852 if self.man: |
986 if self.man: |
853 genman(root) |
987 genman(root) |
854 if self.html: |
988 if self.html: |
855 genhtml(root) |
989 genhtml(root) |
856 |
990 |
991 |
|
857 class hginstall(install): |
992 class hginstall(install): |
858 |
993 |
859 user_options = install.user_options + [ |
994 user_options = install.user_options + [ |
860 ('old-and-unmanageable', None, |
995 ( |
861 'noop, present for eggless setuptools compat'), |
996 'old-and-unmanageable', |
862 ('single-version-externally-managed', None, |
997 None, |
863 'noop, present for eggless setuptools compat'), |
998 'noop, present for eggless setuptools compat', |
999 ), |
|
1000 ( |
|
1001 'single-version-externally-managed', |
|
1002 None, |
|
1003 'noop, present for eggless setuptools compat', |
|
1004 ), |
|
864 ] |
1005 ] |
865 |
1006 |
866 # Also helps setuptools not be sad while we refuse to create eggs. |
1007 # Also helps setuptools not be sad while we refuse to create eggs. |
867 single_version_externally_managed = True |
1008 single_version_externally_managed = True |
868 |
1009 |
870 # Screen out egg related commands to prevent egg generation. But allow |
1011 # Screen out egg related commands to prevent egg generation. But allow |
871 # mercurial.egg-info generation, since that is part of modern |
1012 # mercurial.egg-info generation, since that is part of modern |
872 # packaging. |
1013 # packaging. |
873 excl = set(['bdist_egg']) |
1014 excl = set(['bdist_egg']) |
874 return filter(lambda x: x not in excl, install.get_sub_commands(self)) |
1015 return filter(lambda x: x not in excl, install.get_sub_commands(self)) |
1016 |
|
875 |
1017 |
876 class hginstalllib(install_lib): |
1018 class hginstalllib(install_lib): |
877 ''' |
1019 ''' |
878 This is a specialization of install_lib that replaces the copy_file used |
1020 This is a specialization of install_lib that replaces the copy_file used |
879 there so that it supports setting the mode of files after copying them, |
1021 there so that it supports setting the mode of files after copying them, |
885 insufficient, as it might still be applying a umask. |
1027 insufficient, as it might still be applying a umask. |
886 ''' |
1028 ''' |
887 |
1029 |
888 def run(self): |
1030 def run(self): |
889 realcopyfile = file_util.copy_file |
1031 realcopyfile = file_util.copy_file |
1032 |
|
890 def copyfileandsetmode(*args, **kwargs): |
1033 def copyfileandsetmode(*args, **kwargs): |
891 src, dst = args[0], args[1] |
1034 src, dst = args[0], args[1] |
892 dst, copied = realcopyfile(*args, **kwargs) |
1035 dst, copied = realcopyfile(*args, **kwargs) |
893 if copied: |
1036 if copied: |
894 st = os.stat(src) |
1037 st = os.stat(src) |
899 else: |
1042 else: |
900 setmode = int('0644', 8) |
1043 setmode = int('0644', 8) |
901 m = stat.S_IMODE(st[stat.ST_MODE]) |
1044 m = stat.S_IMODE(st[stat.ST_MODE]) |
902 m = (m & ~int('0777', 8)) | setmode |
1045 m = (m & ~int('0777', 8)) | setmode |
903 os.chmod(dst, m) |
1046 os.chmod(dst, m) |
1047 |
|
904 file_util.copy_file = copyfileandsetmode |
1048 file_util.copy_file = copyfileandsetmode |
905 try: |
1049 try: |
906 install_lib.run(self) |
1050 install_lib.run(self) |
907 finally: |
1051 finally: |
908 file_util.copy_file = realcopyfile |
1052 file_util.copy_file = realcopyfile |
1053 |
|
909 |
1054 |
910 class hginstallscripts(install_scripts): |
1055 class hginstallscripts(install_scripts): |
911 ''' |
1056 ''' |
912 This is a specialization of install_scripts that replaces the @LIBDIR@ with |
1057 This is a specialization of install_scripts that replaces the @LIBDIR@ with |
913 the configured directory for modules. If possible, the path is made relative |
1058 the configured directory for modules. If possible, the path is made relative |
919 |
1064 |
920 self.install_lib = None |
1065 self.install_lib = None |
921 |
1066 |
922 def finalize_options(self): |
1067 def finalize_options(self): |
923 install_scripts.finalize_options(self) |
1068 install_scripts.finalize_options(self) |
924 self.set_undefined_options('install', |
1069 self.set_undefined_options('install', ('install_lib', 'install_lib')) |
925 ('install_lib', 'install_lib')) |
|
926 |
1070 |
927 def run(self): |
1071 def run(self): |
928 install_scripts.run(self) |
1072 install_scripts.run(self) |
929 |
1073 |
930 # It only makes sense to replace @LIBDIR@ with the install path if |
1074 # It only makes sense to replace @LIBDIR@ with the install path if |
944 # will be. And, wheels don't appear to provide the ability to register |
1088 # will be. And, wheels don't appear to provide the ability to register |
945 # custom code to run during wheel installation. This all means that |
1089 # custom code to run during wheel installation. This all means that |
946 # we can't reliably set the libdir in wheels: the default behavior |
1090 # we can't reliably set the libdir in wheels: the default behavior |
947 # of looking in sys.path must do. |
1091 # of looking in sys.path must do. |
948 |
1092 |
949 if (os.path.splitdrive(self.install_dir)[0] != |
1093 if ( |
950 os.path.splitdrive(self.install_lib)[0]): |
1094 os.path.splitdrive(self.install_dir)[0] |
1095 != os.path.splitdrive(self.install_lib)[0] |
|
1096 ): |
|
951 # can't make relative paths from one drive to another, so use an |
1097 # can't make relative paths from one drive to another, so use an |
952 # absolute path instead |
1098 # absolute path instead |
953 libdir = self.install_lib |
1099 libdir = self.install_lib |
954 else: |
1100 else: |
955 common = os.path.commonprefix((self.install_dir, self.install_lib)) |
1101 common = os.path.commonprefix((self.install_dir, self.install_lib)) |
956 rest = self.install_dir[len(common):] |
1102 rest = self.install_dir[len(common) :] |
957 uplevel = len([n for n in os.path.split(rest) if n]) |
1103 uplevel = len([n for n in os.path.split(rest) if n]) |
958 |
1104 |
959 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):] |
1105 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common) :] |
960 |
1106 |
961 for outfile in self.outfiles: |
1107 for outfile in self.outfiles: |
962 with open(outfile, 'rb') as fp: |
1108 with open(outfile, 'rb') as fp: |
963 data = fp.read() |
1109 data = fp.read() |
964 |
1110 |
968 |
1114 |
969 # During local installs, the shebang will be rewritten to the final |
1115 # During local installs, the shebang will be rewritten to the final |
970 # install path. During wheel packaging, the shebang has a special |
1116 # install path. During wheel packaging, the shebang has a special |
971 # value. |
1117 # value. |
972 if data.startswith(b'#!python'): |
1118 if data.startswith(b'#!python'): |
973 log.info('not rewriting @LIBDIR@ in %s because install path ' |
1119 log.info( |
974 'not known' % outfile) |
1120 'not rewriting @LIBDIR@ in %s because install path ' |
1121 'not known' % outfile |
|
1122 ) |
|
975 continue |
1123 continue |
976 |
1124 |
977 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape)) |
1125 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape)) |
978 with open(outfile, 'wb') as fp: |
1126 with open(outfile, 'wb') as fp: |
979 fp.write(data) |
1127 fp.write(data) |
1128 |
|
980 |
1129 |
981 # virtualenv installs custom distutils/__init__.py and |
1130 # virtualenv installs custom distutils/__init__.py and |
982 # distutils/distutils.cfg files which essentially proxy back to the |
1131 # distutils/distutils.cfg files which essentially proxy back to the |
983 # "real" distutils in the main Python install. The presence of this |
1132 # "real" distutils in the main Python install. The presence of this |
984 # directory causes py2exe to pick up the "hacked" distutils package |
1133 # directory causes py2exe to pick up the "hacked" distutils package |
1018 modules[k] = v |
1167 modules[k] = v |
1019 |
1168 |
1020 res.modules = modules |
1169 res.modules = modules |
1021 |
1170 |
1022 import opcode |
1171 import opcode |
1023 distutilsreal = os.path.join(os.path.dirname(opcode.__file__), |
1172 |
1024 'distutils') |
1173 distutilsreal = os.path.join( |
1174 os.path.dirname(opcode.__file__), 'distutils' |
|
1175 ) |
|
1025 |
1176 |
1026 for root, dirs, files in os.walk(distutilsreal): |
1177 for root, dirs, files in os.walk(distutilsreal): |
1027 for f in sorted(files): |
1178 for f in sorted(files): |
1028 if not f.endswith('.py'): |
1179 if not f.endswith('.py'): |
1029 continue |
1180 continue |
1040 |
1191 |
1041 if modname.startswith('distutils.tests.'): |
1192 if modname.startswith('distutils.tests.'): |
1042 continue |
1193 continue |
1043 |
1194 |
1044 if modname.endswith('.__init__'): |
1195 if modname.endswith('.__init__'): |
1045 modname = modname[:-len('.__init__')] |
1196 modname = modname[: -len('.__init__')] |
1046 path = os.path.dirname(full) |
1197 path = os.path.dirname(full) |
1047 else: |
1198 else: |
1048 path = None |
1199 path = None |
1049 |
1200 |
1050 res.modules[modname] = py2exemodule(modname, full, |
1201 res.modules[modname] = py2exemodule( |
1051 path=path) |
1202 modname, full, path=path |
1203 ) |
|
1052 |
1204 |
1053 if 'distutils' not in res.modules: |
1205 if 'distutils' not in res.modules: |
1054 raise SystemExit('could not find distutils modules') |
1206 raise SystemExit('could not find distutils modules') |
1055 |
1207 |
1056 return res |
1208 return res |
1057 |
1209 |
1058 cmdclass = {'build': hgbuild, |
1210 |
1059 'build_doc': hgbuilddoc, |
1211 cmdclass = { |
1060 'build_mo': hgbuildmo, |
1212 'build': hgbuild, |
1061 'build_ext': hgbuildext, |
1213 'build_doc': hgbuilddoc, |
1062 'build_py': hgbuildpy, |
1214 'build_mo': hgbuildmo, |
1063 'build_scripts': hgbuildscripts, |
1215 'build_ext': hgbuildext, |
1064 'build_hgextindex': buildhgextindex, |
1216 'build_py': hgbuildpy, |
1065 'install': hginstall, |
1217 'build_scripts': hgbuildscripts, |
1066 'install_lib': hginstalllib, |
1218 'build_hgextindex': buildhgextindex, |
1067 'install_scripts': hginstallscripts, |
1219 'install': hginstall, |
1068 'build_hgexe': buildhgexe, |
1220 'install_lib': hginstalllib, |
1069 } |
1221 'install_scripts': hginstallscripts, |
1222 'build_hgexe': buildhgexe, |
|
1223 } |
|
1070 |
1224 |
1071 if py2exehacked: |
1225 if py2exehacked: |
1072 cmdclass['py2exe'] = hgbuildpy2exe |
1226 cmdclass['py2exe'] = hgbuildpy2exe |
1073 |
1227 |
1074 packages = ['mercurial', |
1228 packages = [ |
1075 'mercurial.cext', |
1229 'mercurial', |
1076 'mercurial.cffi', |
1230 'mercurial.cext', |
1077 'mercurial.hgweb', |
1231 'mercurial.cffi', |
1078 'mercurial.interfaces', |
1232 'mercurial.hgweb', |
1079 'mercurial.pure', |
1233 'mercurial.interfaces', |
1080 'mercurial.thirdparty', |
1234 'mercurial.pure', |
1081 'mercurial.thirdparty.attr', |
1235 'mercurial.thirdparty', |
1082 'mercurial.thirdparty.zope', |
1236 'mercurial.thirdparty.attr', |
1083 'mercurial.thirdparty.zope.interface', |
1237 'mercurial.thirdparty.zope', |
1084 'mercurial.utils', |
1238 'mercurial.thirdparty.zope.interface', |
1085 'mercurial.revlogutils', |
1239 'mercurial.utils', |
1086 'mercurial.testing', |
1240 'mercurial.revlogutils', |
1087 'hgext', 'hgext.convert', 'hgext.fsmonitor', |
1241 'mercurial.testing', |
1088 'hgext.fastannotate', |
1242 'hgext', |
1089 'hgext.fsmonitor.pywatchman', |
1243 'hgext.convert', |
1090 'hgext.highlight', |
1244 'hgext.fsmonitor', |
1091 'hgext.infinitepush', |
1245 'hgext.fastannotate', |
1092 'hgext.largefiles', 'hgext.lfs', 'hgext.narrow', |
1246 'hgext.fsmonitor.pywatchman', |
1093 'hgext.remotefilelog', |
1247 'hgext.highlight', |
1094 'hgext.zeroconf', 'hgext3rd', |
1248 'hgext.infinitepush', |
1095 'hgdemandimport'] |
1249 'hgext.largefiles', |
1250 'hgext.lfs', |
|
1251 'hgext.narrow', |
|
1252 'hgext.remotefilelog', |
|
1253 'hgext.zeroconf', |
|
1254 'hgext3rd', |
|
1255 'hgdemandimport', |
|
1256 ] |
|
1096 if sys.version_info[0] == 2: |
1257 if sys.version_info[0] == 2: |
1097 packages.extend(['mercurial.thirdparty.concurrent', |
1258 packages.extend( |
1098 'mercurial.thirdparty.concurrent.futures']) |
1259 [ |
1260 'mercurial.thirdparty.concurrent', |
|
1261 'mercurial.thirdparty.concurrent.futures', |
|
1262 ] |
|
1263 ) |
|
1099 |
1264 |
1100 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ: |
1265 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ: |
1101 # py2exe can't cope with namespace packages very well, so we have to |
1266 # py2exe can't cope with namespace packages very well, so we have to |
1102 # install any hgext3rd.* extensions that we want in the final py2exe |
1267 # install any hgext3rd.* extensions that we want in the final py2exe |
1103 # image here. This is gross, but you gotta do what you gotta do. |
1268 # image here. This is gross, but you gotta do what you gotta do. |
1104 packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' ')) |
1269 packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' ')) |
1105 |
1270 |
1106 common_depends = ['mercurial/bitmanipulation.h', |
1271 common_depends = [ |
1107 'mercurial/compat.h', |
1272 'mercurial/bitmanipulation.h', |
1108 'mercurial/cext/util.h'] |
1273 'mercurial/compat.h', |
1274 'mercurial/cext/util.h', |
|
1275 ] |
|
1109 common_include_dirs = ['mercurial'] |
1276 common_include_dirs = ['mercurial'] |
1110 |
1277 |
1111 osutil_cflags = [] |
1278 osutil_cflags = [] |
1112 osutil_ldflags = [] |
1279 osutil_ldflags = [] |
1113 |
1280 |
1115 for plat, func in [('bsd', 'setproctitle')]: |
1282 for plat, func in [('bsd', 'setproctitle')]: |
1116 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func): |
1283 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func): |
1117 osutil_cflags.append('-DHAVE_%s' % func.upper()) |
1284 osutil_cflags.append('-DHAVE_%s' % func.upper()) |
1118 |
1285 |
1119 for plat, macro, code in [ |
1286 for plat, macro, code in [ |
1120 ('bsd|darwin', 'BSD_STATFS', ''' |
1287 ( |
1288 'bsd|darwin', |
|
1289 'BSD_STATFS', |
|
1290 ''' |
|
1121 #include <sys/param.h> |
1291 #include <sys/param.h> |
1122 #include <sys/mount.h> |
1292 #include <sys/mount.h> |
1123 int main() { struct statfs s; return sizeof(s.f_fstypename); } |
1293 int main() { struct statfs s; return sizeof(s.f_fstypename); } |
1124 '''), |
1294 ''', |
1125 ('linux', 'LINUX_STATFS', ''' |
1295 ), |
1296 ( |
|
1297 'linux', |
|
1298 'LINUX_STATFS', |
|
1299 ''' |
|
1126 #include <linux/magic.h> |
1300 #include <linux/magic.h> |
1127 #include <sys/vfs.h> |
1301 #include <sys/vfs.h> |
1128 int main() { struct statfs s; return sizeof(s.f_type); } |
1302 int main() { struct statfs s; return sizeof(s.f_type); } |
1129 '''), |
1303 ''', |
1304 ), |
|
1130 ]: |
1305 ]: |
1131 if re.search(plat, sys.platform) and cancompile(new_compiler(), code): |
1306 if re.search(plat, sys.platform) and cancompile(new_compiler(), code): |
1132 osutil_cflags.append('-DHAVE_%s' % macro) |
1307 osutil_cflags.append('-DHAVE_%s' % macro) |
1133 |
1308 |
1134 if sys.platform == 'darwin': |
1309 if sys.platform == 'darwin': |
1148 'mercurial/thirdparty/xdiff/xprepare.h', |
1323 'mercurial/thirdparty/xdiff/xprepare.h', |
1149 'mercurial/thirdparty/xdiff/xtypes.h', |
1324 'mercurial/thirdparty/xdiff/xtypes.h', |
1150 'mercurial/thirdparty/xdiff/xutils.h', |
1325 'mercurial/thirdparty/xdiff/xutils.h', |
1151 ] |
1326 ] |
1152 |
1327 |
1328 |
|
1153 class RustCompilationError(CCompilerError): |
1329 class RustCompilationError(CCompilerError): |
1154 """Exception class for Rust compilation errors.""" |
1330 """Exception class for Rust compilation errors.""" |
1331 |
|
1155 |
1332 |
1156 class RustExtension(Extension): |
1333 class RustExtension(Extension): |
1157 """Base classes for concrete Rust Extension classes. |
1334 """Base classes for concrete Rust Extension classes. |
1158 """ |
1335 """ |
1159 |
1336 |
1160 rusttargetdir = os.path.join('rust', 'target', 'release') |
1337 rusttargetdir = os.path.join('rust', 'target', 'release') |
1161 |
1338 |
1162 def __init__(self, mpath, sources, rustlibname, subcrate, |
1339 def __init__( |
1163 py3_features=None, **kw): |
1340 self, mpath, sources, rustlibname, subcrate, py3_features=None, **kw |
1341 ): |
|
1164 Extension.__init__(self, mpath, sources, **kw) |
1342 Extension.__init__(self, mpath, sources, **kw) |
1165 srcdir = self.rustsrcdir = os.path.join('rust', subcrate) |
1343 srcdir = self.rustsrcdir = os.path.join('rust', subcrate) |
1166 self.py3_features = py3_features |
1344 self.py3_features = py3_features |
1167 |
1345 |
1168 # adding Rust source and control files to depends so that the extension |
1346 # adding Rust source and control files to depends so that the extension |
1170 self.depends.append(os.path.join(srcdir, 'Cargo.toml')) |
1348 self.depends.append(os.path.join(srcdir, 'Cargo.toml')) |
1171 cargo_lock = os.path.join(srcdir, 'Cargo.lock') |
1349 cargo_lock = os.path.join(srcdir, 'Cargo.lock') |
1172 if os.path.exists(cargo_lock): |
1350 if os.path.exists(cargo_lock): |
1173 self.depends.append(cargo_lock) |
1351 self.depends.append(cargo_lock) |
1174 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')): |
1352 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')): |
1175 self.depends.extend(os.path.join(dirpath, fname) |
1353 self.depends.extend( |
1176 for fname in fnames |
1354 os.path.join(dirpath, fname) |
1177 if os.path.splitext(fname)[1] == '.rs') |
1355 for fname in fnames |
1356 if os.path.splitext(fname)[1] == '.rs' |
|
1357 ) |
|
1178 |
1358 |
1179 @staticmethod |
1359 @staticmethod |
1180 def rustdylibsuffix(): |
1360 def rustdylibsuffix(): |
1181 """Return the suffix for shared libraries produced by rustc. |
1361 """Return the suffix for shared libraries produced by rustc. |
1182 |
1362 |
1200 # invoke this build. |
1380 # invoke this build. |
1201 |
1381 |
1202 # Unix only fix (os.path.expanduser not really reliable if |
1382 # Unix only fix (os.path.expanduser not really reliable if |
1203 # HOME is shadowed like this) |
1383 # HOME is shadowed like this) |
1204 import pwd |
1384 import pwd |
1385 |
|
1205 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir |
1386 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir |
1206 |
1387 |
1207 cargocmd = ['cargo', 'rustc', '-vv', '--release'] |
1388 cargocmd = ['cargo', 'rustc', '-vv', '--release'] |
1208 if sys.version_info[0] == 3 and self.py3_features is not None: |
1389 if sys.version_info[0] == 3 and self.py3_features is not None: |
1209 cargocmd.extend(('--features', self.py3_features, |
1390 cargocmd.extend( |
1210 '--no-default-features')) |
1391 ('--features', self.py3_features, '--no-default-features') |
1392 ) |
|
1211 cargocmd.append('--') |
1393 cargocmd.append('--') |
1212 if sys.platform == 'darwin': |
1394 if sys.platform == 'darwin': |
1213 cargocmd.extend(("-C", "link-arg=-undefined", |
1395 cargocmd.extend( |
1214 "-C", "link-arg=dynamic_lookup")) |
1396 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup") |
1397 ) |
|
1215 try: |
1398 try: |
1216 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir) |
1399 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir) |
1217 except OSError as exc: |
1400 except OSError as exc: |
1218 if exc.errno == errno.ENOENT: |
1401 if exc.errno == errno.ENOENT: |
1219 raise RustCompilationError("Cargo not found") |
1402 raise RustCompilationError("Cargo not found") |
1220 elif exc.errno == errno.EACCES: |
1403 elif exc.errno == errno.EACCES: |
1221 raise RustCompilationError( |
1404 raise RustCompilationError( |
1222 "Cargo found, but permisssion to execute it is denied") |
1405 "Cargo found, but permisssion to execute it is denied" |
1406 ) |
|
1223 else: |
1407 else: |
1224 raise |
1408 raise |
1225 except subprocess.CalledProcessError: |
1409 except subprocess.CalledProcessError: |
1226 raise RustCompilationError( |
1410 raise RustCompilationError( |
1227 "Cargo failed. Working directory: %r, " |
1411 "Cargo failed. Working directory: %r, " |
1228 "command: %r, environment: %r" |
1412 "command: %r, environment: %r" |
1229 % (self.rustsrcdir, cargocmd, env)) |
1413 % (self.rustsrcdir, cargocmd, env) |
1414 ) |
|
1415 |
|
1230 |
1416 |
1231 class RustEnhancedExtension(RustExtension): |
1417 class RustEnhancedExtension(RustExtension): |
1232 """A C Extension, conditionally enhanced with Rust code. |
1418 """A C Extension, conditionally enhanced with Rust code. |
1233 |
1419 |
1234 If the HGRUSTEXT environment variable is set to something else |
1420 If the HGRUSTEXT environment variable is set to something else |
1235 than 'cpython', the Rust sources get compiled and linked within the |
1421 than 'cpython', the Rust sources get compiled and linked within the |
1236 C target shared library object. |
1422 C target shared library object. |
1237 """ |
1423 """ |
1238 |
1424 |
1239 def __init__(self, mpath, sources, rustlibname, subcrate, **kw): |
1425 def __init__(self, mpath, sources, rustlibname, subcrate, **kw): |
1240 RustExtension.__init__(self, mpath, sources, rustlibname, subcrate, |
1426 RustExtension.__init__( |
1241 **kw) |
1427 self, mpath, sources, rustlibname, subcrate, **kw |
1428 ) |
|
1242 if hgrustext != 'direct-ffi': |
1429 if hgrustext != 'direct-ffi': |
1243 return |
1430 return |
1244 self.extra_compile_args.append('-DWITH_RUST') |
1431 self.extra_compile_args.append('-DWITH_RUST') |
1245 self.libraries.append(rustlibname) |
1432 self.libraries.append(rustlibname) |
1246 self.library_dirs.append(self.rusttargetdir) |
1433 self.library_dirs.append(self.rusttargetdir) |
1247 |
1434 |
1248 def rustbuild(self): |
1435 def rustbuild(self): |
1249 if hgrustext == 'direct-ffi': |
1436 if hgrustext == 'direct-ffi': |
1250 RustExtension.rustbuild(self) |
1437 RustExtension.rustbuild(self) |
1251 |
1438 |
1439 |
|
1252 class RustStandaloneExtension(RustExtension): |
1440 class RustStandaloneExtension(RustExtension): |
1253 |
|
1254 def __init__(self, pydottedname, rustcrate, dylibname, **kw): |
1441 def __init__(self, pydottedname, rustcrate, dylibname, **kw): |
1255 RustExtension.__init__(self, pydottedname, [], dylibname, rustcrate, |
1442 RustExtension.__init__( |
1256 **kw) |
1443 self, pydottedname, [], dylibname, rustcrate, **kw |
1444 ) |
|
1257 self.dylibname = dylibname |
1445 self.dylibname = dylibname |
1258 |
1446 |
1259 def build(self, target_dir): |
1447 def build(self, target_dir): |
1260 self.rustbuild() |
1448 self.rustbuild() |
1261 target = [target_dir] |
1449 target = [target_dir] |
1262 target.extend(self.name.split('.')) |
1450 target.extend(self.name.split('.')) |
1263 target[-1] += DYLIB_SUFFIX |
1451 target[-1] += DYLIB_SUFFIX |
1264 shutil.copy2(os.path.join(self.rusttargetdir, |
1452 shutil.copy2( |
1265 self.dylibname + self.rustdylibsuffix()), |
1453 os.path.join( |
1266 os.path.join(*target)) |
1454 self.rusttargetdir, self.dylibname + self.rustdylibsuffix() |
1455 ), |
|
1456 os.path.join(*target), |
|
1457 ) |
|
1267 |
1458 |
1268 |
1459 |
1269 extmodules = [ |
1460 extmodules = [ |
1270 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'], |
1461 Extension( |
1271 include_dirs=common_include_dirs, |
1462 'mercurial.cext.base85', |
1272 depends=common_depends), |
1463 ['mercurial/cext/base85.c'], |
1273 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c', |
1464 include_dirs=common_include_dirs, |
1274 'mercurial/cext/bdiff.c'] + xdiff_srcs, |
1465 depends=common_depends, |
1275 include_dirs=common_include_dirs, |
1466 ), |
1276 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers), |
1467 Extension( |
1277 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c', |
1468 'mercurial.cext.bdiff', |
1278 'mercurial/cext/mpatch.c'], |
1469 ['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs, |
1279 include_dirs=common_include_dirs, |
1470 include_dirs=common_include_dirs, |
1280 depends=common_depends), |
1471 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers, |
1472 ), |
|
1473 Extension( |
|
1474 'mercurial.cext.mpatch', |
|
1475 ['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'], |
|
1476 include_dirs=common_include_dirs, |
|
1477 depends=common_depends, |
|
1478 ), |
|
1281 RustEnhancedExtension( |
1479 RustEnhancedExtension( |
1282 'mercurial.cext.parsers', ['mercurial/cext/charencode.c', |
1480 'mercurial.cext.parsers', |
1283 'mercurial/cext/dirs.c', |
1481 [ |
1284 'mercurial/cext/manifest.c', |
1482 'mercurial/cext/charencode.c', |
1285 'mercurial/cext/parsers.c', |
1483 'mercurial/cext/dirs.c', |
1286 'mercurial/cext/pathencode.c', |
1484 'mercurial/cext/manifest.c', |
1287 'mercurial/cext/revlog.c'], |
1485 'mercurial/cext/parsers.c', |
1486 'mercurial/cext/pathencode.c', |
|
1487 'mercurial/cext/revlog.c', |
|
1488 ], |
|
1288 'hgdirectffi', |
1489 'hgdirectffi', |
1289 'hg-direct-ffi', |
1490 'hg-direct-ffi', |
1290 include_dirs=common_include_dirs, |
1491 include_dirs=common_include_dirs, |
1291 depends=common_depends + ['mercurial/cext/charencode.h', |
1492 depends=common_depends |
1292 'mercurial/cext/revlog.h', |
1493 + [ |
1293 'rust/hg-core/src/ancestors.rs', |
1494 'mercurial/cext/charencode.h', |
1294 'rust/hg-core/src/lib.rs']), |
1495 'mercurial/cext/revlog.h', |
1295 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'], |
1496 'rust/hg-core/src/ancestors.rs', |
1296 include_dirs=common_include_dirs, |
1497 'rust/hg-core/src/lib.rs', |
1297 extra_compile_args=osutil_cflags, |
1498 ], |
1298 extra_link_args=osutil_ldflags, |
1499 ), |
1299 depends=common_depends), |
|
1300 Extension( |
1500 Extension( |
1301 'mercurial.thirdparty.zope.interface._zope_interface_coptimizations', [ |
1501 'mercurial.cext.osutil', |
1302 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c', |
1502 ['mercurial/cext/osutil.c'], |
1303 ]), |
1503 include_dirs=common_include_dirs, |
1304 Extension('hgext.fsmonitor.pywatchman.bser', |
1504 extra_compile_args=osutil_cflags, |
1305 ['hgext/fsmonitor/pywatchman/bser.c']), |
1505 extra_link_args=osutil_ldflags, |
1306 RustStandaloneExtension('mercurial.rustext', 'hg-cpython', 'librusthg', |
1506 depends=common_depends, |
1307 py3_features='python3'), |
1507 ), |
1308 ] |
1508 Extension( |
1509 'mercurial.thirdparty.zope.interface._zope_interface_coptimizations', |
|
1510 [ |
|
1511 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c', |
|
1512 ], |
|
1513 ), |
|
1514 Extension( |
|
1515 'hgext.fsmonitor.pywatchman.bser', ['hgext/fsmonitor/pywatchman/bser.c'] |
|
1516 ), |
|
1517 RustStandaloneExtension( |
|
1518 'mercurial.rustext', 'hg-cpython', 'librusthg', py3_features='python3' |
|
1519 ), |
|
1520 ] |
|
1309 |
1521 |
1310 |
1522 |
1311 sys.path.insert(0, 'contrib/python-zstandard') |
1523 sys.path.insert(0, 'contrib/python-zstandard') |
1312 import setup_zstd |
1524 import setup_zstd |
1313 extmodules.append(setup_zstd.get_c_extension( |
1525 |
1314 name='mercurial.zstd', |
1526 extmodules.append( |
1315 root=os.path.abspath(os.path.dirname(__file__)))) |
1527 setup_zstd.get_c_extension( |
1528 name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__)) |
|
1529 ) |
|
1530 ) |
|
1316 |
1531 |
1317 try: |
1532 try: |
1318 from distutils import cygwinccompiler |
1533 from distutils import cygwinccompiler |
1319 |
1534 |
1320 # the -mno-cygwin option has been deprecated for years |
1535 # the -mno-cygwin option has been deprecated for years |
1335 # distributions like the ones from the optware project for Synology |
1550 # distributions like the ones from the optware project for Synology |
1336 # DiskStation boxes |
1551 # DiskStation boxes |
1337 class HackedMingw32CCompiler(object): |
1552 class HackedMingw32CCompiler(object): |
1338 pass |
1553 pass |
1339 |
1554 |
1555 |
|
1340 if os.name == 'nt': |
1556 if os.name == 'nt': |
1341 # Allow compiler/linker flags to be added to Visual Studio builds. Passing |
1557 # Allow compiler/linker flags to be added to Visual Studio builds. Passing |
1342 # extra_link_args to distutils.extensions.Extension() doesn't have any |
1558 # extra_link_args to distutils.extensions.Extension() doesn't have any |
1343 # effect. |
1559 # effect. |
1344 from distutils import msvccompiler |
1560 from distutils import msvccompiler |
1352 self.ldflags_shared.append('/ignore:4197') |
1568 self.ldflags_shared.append('/ignore:4197') |
1353 self.ldflags_shared_debug.append('/ignore:4197') |
1569 self.ldflags_shared_debug.append('/ignore:4197') |
1354 |
1570 |
1355 msvccompiler.MSVCCompiler = HackedMSVCCompiler |
1571 msvccompiler.MSVCCompiler = HackedMSVCCompiler |
1356 |
1572 |
1357 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo', |
1573 packagedata = { |
1358 'help/*.txt', |
1574 'mercurial': [ |
1359 'help/internals/*.txt', |
1575 'locale/*/LC_MESSAGES/hg.mo', |
1360 'default.d/*.rc', |
1576 'help/*.txt', |
1361 'dummycert.pem']} |
1577 'help/internals/*.txt', |
1578 'default.d/*.rc', |
|
1579 'dummycert.pem', |
|
1580 ] |
|
1581 } |
|
1582 |
|
1362 |
1583 |
1363 def ordinarypath(p): |
1584 def ordinarypath(p): |
1364 return p and p[0] != '.' and p[-1] != '~' |
1585 return p and p[0] != '.' and p[-1] != '~' |
1586 |
|
1365 |
1587 |
1366 for root in ('templates',): |
1588 for root in ('templates',): |
1367 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)): |
1589 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)): |
1368 curdir = curdir.split(os.sep, 1)[1] |
1590 curdir = curdir.split(os.sep, 1)[1] |
1369 dirs[:] = filter(ordinarypath, dirs) |
1591 dirs[:] = filter(ordinarypath, dirs) |
1400 if issetuptools: |
1622 if issetuptools: |
1401 extra['python_requires'] = supportedpy |
1623 extra['python_requires'] = supportedpy |
1402 |
1624 |
1403 if py2exeloaded: |
1625 if py2exeloaded: |
1404 extra['console'] = [ |
1626 extra['console'] = [ |
1405 {'script':'hg', |
1627 { |
1406 'copyright':'Copyright (C) 2005-2019 Matt Mackall and others', |
1628 'script': 'hg', |
1407 'product_version':version}] |
1629 'copyright': 'Copyright (C) 2005-2019 Matt Mackall and others', |
1630 'product_version': version, |
|
1631 } |
|
1632 ] |
|
1408 # Sub command of 'build' because 'py2exe' does not handle sub_commands. |
1633 # Sub command of 'build' because 'py2exe' does not handle sub_commands. |
1409 # Need to override hgbuild because it has a private copy of |
1634 # Need to override hgbuild because it has a private copy of |
1410 # build.sub_commands. |
1635 # build.sub_commands. |
1411 hgbuild.sub_commands.insert(0, ('build_hgextindex', None)) |
1636 hgbuild.sub_commands.insert(0, ('build_hgextindex', None)) |
1412 # put dlls in sub directory so that they won't pollute PATH |
1637 # put dlls in sub directory so that they won't pollute PATH |
1436 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines() |
1661 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines() |
1437 if version: |
1662 if version: |
1438 version = version[0] |
1663 version = version[0] |
1439 if sys.version_info[0] == 3: |
1664 if sys.version_info[0] == 3: |
1440 version = version.decode('utf-8') |
1665 version = version.decode('utf-8') |
1441 xcode4 = (version.startswith('Xcode') and |
1666 xcode4 = version.startswith('Xcode') and StrictVersion( |
1442 StrictVersion(version.split()[1]) >= StrictVersion('4.0')) |
1667 version.split()[1] |
1668 ) >= StrictVersion('4.0') |
|
1443 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None |
1669 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None |
1444 else: |
1670 else: |
1445 # xcodebuild returns empty on OS X Lion with XCode 4.3 not |
1671 # xcodebuild returns empty on OS X Lion with XCode 4.3 not |
1446 # installed, but instead with only command-line tools. Assume |
1672 # installed, but instead with only command-line tools. Assume |
1447 # that only happens on >= Lion, thus no PPC support. |
1673 # that only happens on >= Lion, thus no PPC support. |
1461 # so Mercurial can continue to compile in the meantime. |
1687 # so Mercurial can continue to compile in the meantime. |
1462 if xcode51: |
1688 if xcode51: |
1463 cflags = get_config_var('CFLAGS') |
1689 cflags = get_config_var('CFLAGS') |
1464 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None: |
1690 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None: |
1465 os.environ['CFLAGS'] = ( |
1691 os.environ['CFLAGS'] = ( |
1466 os.environ.get('CFLAGS', '') + ' -Qunused-arguments') |
1692 os.environ.get('CFLAGS', '') + ' -Qunused-arguments' |
1467 |
1693 ) |
1468 setup(name='mercurial', |
1694 |
1469 version=setupversion, |
1695 setup( |
1470 author='Matt Mackall and many others', |
1696 name='mercurial', |
1471 author_email='mercurial@mercurial-scm.org', |
1697 version=setupversion, |
1472 url='https://mercurial-scm.org/', |
1698 author='Matt Mackall and many others', |
1473 download_url='https://mercurial-scm.org/release/', |
1699 author_email='mercurial@mercurial-scm.org', |
1474 description=('Fast scalable distributed SCM (revision control, version ' |
1700 url='https://mercurial-scm.org/', |
1475 'control) system'), |
1701 download_url='https://mercurial-scm.org/release/', |
1476 long_description=('Mercurial is a distributed SCM tool written in Python.' |
1702 description=( |
1477 ' It is used by a number of large projects that require' |
1703 'Fast scalable distributed SCM (revision control, version ' |
1478 ' fast, reliable distributed revision control, such as ' |
1704 'control) system' |
1479 'Mozilla.'), |
1705 ), |
1480 license='GNU GPLv2 or any later version', |
1706 long_description=( |
1481 classifiers=[ |
1707 'Mercurial is a distributed SCM tool written in Python.' |
1482 'Development Status :: 6 - Mature', |
1708 ' It is used by a number of large projects that require' |
1483 'Environment :: Console', |
1709 ' fast, reliable distributed revision control, such as ' |
1484 'Intended Audience :: Developers', |
1710 'Mozilla.' |
1485 'Intended Audience :: System Administrators', |
1711 ), |
1486 'License :: OSI Approved :: GNU General Public License (GPL)', |
1712 license='GNU GPLv2 or any later version', |
1487 'Natural Language :: Danish', |
1713 classifiers=[ |
1488 'Natural Language :: English', |
1714 'Development Status :: 6 - Mature', |
1489 'Natural Language :: German', |
1715 'Environment :: Console', |
1490 'Natural Language :: Italian', |
1716 'Intended Audience :: Developers', |
1491 'Natural Language :: Japanese', |
1717 'Intended Audience :: System Administrators', |
1492 'Natural Language :: Portuguese (Brazilian)', |
1718 'License :: OSI Approved :: GNU General Public License (GPL)', |
1493 'Operating System :: Microsoft :: Windows', |
1719 'Natural Language :: Danish', |
1494 'Operating System :: OS Independent', |
1720 'Natural Language :: English', |
1495 'Operating System :: POSIX', |
1721 'Natural Language :: German', |
1496 'Programming Language :: C', |
1722 'Natural Language :: Italian', |
1497 'Programming Language :: Python', |
1723 'Natural Language :: Japanese', |
1498 'Topic :: Software Development :: Version Control', |
1724 'Natural Language :: Portuguese (Brazilian)', |
1499 ], |
1725 'Operating System :: Microsoft :: Windows', |
1500 scripts=scripts, |
1726 'Operating System :: OS Independent', |
1501 packages=packages, |
1727 'Operating System :: POSIX', |
1502 ext_modules=extmodules, |
1728 'Programming Language :: C', |
1503 data_files=datafiles, |
1729 'Programming Language :: Python', |
1504 package_data=packagedata, |
1730 'Topic :: Software Development :: Version Control', |
1505 cmdclass=cmdclass, |
1731 ], |
1506 distclass=hgdist, |
1732 scripts=scripts, |
1507 options={ |
1733 packages=packages, |
1508 'py2exe': { |
1734 ext_modules=extmodules, |
1509 'bundle_files': 3, |
1735 data_files=datafiles, |
1510 'dll_excludes': py2exedllexcludes, |
1736 package_data=packagedata, |
1511 'excludes': py2exeexcludes, |
1737 cmdclass=cmdclass, |
1512 'packages': py2exepackages, |
1738 distclass=hgdist, |
1513 }, |
1739 options={ |
1514 'bdist_mpkg': { |
1740 'py2exe': { |
1515 'zipdist': False, |
1741 'bundle_files': 3, |
1516 'license': 'COPYING', |
1742 'dll_excludes': py2exedllexcludes, |
1517 'readme': 'contrib/packaging/macosx/Readme.html', |
1743 'excludes': py2exeexcludes, |
1518 'welcome': 'contrib/packaging/macosx/Welcome.html', |
1744 'packages': py2exepackages, |
1519 }, |
1745 }, |
1520 }, |
1746 'bdist_mpkg': { |
1521 **extra) |
1747 'zipdist': False, |
1748 'license': 'COPYING', |
|
1749 'readme': 'contrib/packaging/macosx/Readme.html', |
|
1750 'welcome': 'contrib/packaging/macosx/Welcome.html', |
|
1751 }, |
|
1752 }, |
|
1753 **extra |
|
1754 ) |