comparison setup.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents f9d35f01b8b3
children c3e10f705a6c
comparison
equal deleted inserted replaced
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 )