3 # |
3 # |
4 # 'python setup.py install', or |
4 # 'python setup.py install', or |
5 # 'python setup.py --help' for more options |
5 # 'python setup.py --help' for more options |
6 import os |
6 import os |
7 |
7 |
8 # Mercurial will never work on Python 3 before 3.5 due to a lack |
8 # Mercurial can't work on 3.6.0 or 3.6.1 due to a bug in % formatting |
9 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1 |
9 # in bytestrings. |
10 # due to a bug in % formatting in bytestrings. |
|
11 # We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in |
|
12 # codecs.escape_encode() where it raises SystemError on empty bytestring |
|
13 # bug link: https://bugs.python.org/issue25270 |
|
14 supportedpy = ','.join( |
10 supportedpy = ','.join( |
15 [ |
11 [ |
16 '>=2.7.4', |
12 '>=3.6.2', |
17 '!=3.0.*', |
|
18 '!=3.1.*', |
|
19 '!=3.2.*', |
|
20 '!=3.3.*', |
|
21 '!=3.4.*', |
|
22 '!=3.5.0', |
|
23 '!=3.5.1', |
|
24 '!=3.5.2', |
|
25 '!=3.6.0', |
|
26 '!=3.6.1', |
|
27 ] |
13 ] |
28 ) |
14 ) |
29 |
15 |
30 import sys, platform |
16 import sys, platform |
31 import sysconfig |
17 import sysconfig |
32 |
18 |
33 if sys.version_info[0] >= 3: |
19 |
34 printf = eval('print') |
20 def sysstr(s): |
35 libdir_escape = 'unicode_escape' |
21 return s.decode('latin-1') |
36 |
22 |
37 def sysstr(s): |
|
38 return s.decode('latin-1') |
|
39 |
|
40 |
|
41 else: |
|
42 libdir_escape = 'string_escape' |
|
43 |
|
44 def printf(*args, **kwargs): |
|
45 f = kwargs.get('file', sys.stdout) |
|
46 end = kwargs.get('end', '\n') |
|
47 f.write(b' '.join(args) + end) |
|
48 |
|
49 def sysstr(s): |
|
50 return s |
|
51 |
|
52 |
|
53 # Attempt to guide users to a modern pip - this means that 2.6 users |
|
54 # should have a chance of getting a 4.2 release, and when we ratchet |
|
55 # the version requirement forward again hopefully everyone will get |
|
56 # something that works for them. |
|
57 if sys.version_info < (2, 7, 4, 'final'): |
|
58 pip_message = ( |
|
59 'This may be due to an out of date pip. ' |
|
60 'Make sure you have pip >= 9.0.1.' |
|
61 ) |
|
62 try: |
|
63 import pip |
|
64 |
|
65 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]]) |
|
66 if pip_version < (9, 0, 1): |
|
67 pip_message = ( |
|
68 'Your pip version is out of date, please install ' |
|
69 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__) |
|
70 ) |
|
71 else: |
|
72 # pip is new enough - it must be something else |
|
73 pip_message = '' |
|
74 except Exception: |
|
75 pass |
|
76 error = """ |
|
77 Mercurial does not support Python older than 2.7.4. |
|
78 Python {py} detected. |
|
79 {pip} |
|
80 """.format( |
|
81 py=sys.version_info, pip=pip_message |
|
82 ) |
|
83 printf(error, file=sys.stderr) |
|
84 sys.exit(1) |
|
85 |
23 |
86 import ssl |
24 import ssl |
87 |
|
88 try: |
|
89 ssl.SSLContext |
|
90 except AttributeError: |
|
91 error = """ |
|
92 The `ssl` module does not have the `SSLContext` class. This indicates an old |
|
93 Python version which does not support modern security features (which were |
|
94 added to Python 2.7 as part of "PEP 466"). Please make sure you have installed |
|
95 at least Python 2.7.9 or a Python version with backports of these security |
|
96 features. |
|
97 """ |
|
98 printf(error, file=sys.stderr) |
|
99 sys.exit(1) |
|
100 |
25 |
101 # ssl.HAS_TLSv1* are preferred to check support but they were added in Python |
26 # ssl.HAS_TLSv1* are preferred to check support but they were added in Python |
102 # 3.7. Prior to CPython commit 6e8cda91d92da72800d891b2fc2073ecbc134d98 |
27 # 3.7. Prior to CPython commit 6e8cda91d92da72800d891b2fc2073ecbc134d98 |
103 # (backported to the 3.7 branch), ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2 |
28 # (backported to the 3.7 branch), ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2 |
104 # were defined only if compiled against a OpenSSL version with TLS 1.1 / 1.2 |
29 # were defined only if compiled against a OpenSSL version with TLS 1.1 / 1.2 |
115 The `ssl` module does not advertise support for TLS 1.1 or TLS 1.2. |
40 The `ssl` module does not advertise support for TLS 1.1 or TLS 1.2. |
116 Please make sure that your Python installation was compiled against an OpenSSL |
41 Please make sure that your Python installation was compiled against an OpenSSL |
117 version enabling these features (likely this requires the OpenSSL version to |
42 version enabling these features (likely this requires the OpenSSL version to |
118 be at least 1.0.1). |
43 be at least 1.0.1). |
119 """ |
44 """ |
120 printf(error, file=sys.stderr) |
45 print(error, file=sys.stderr) |
121 sys.exit(1) |
46 sys.exit(1) |
122 |
47 |
123 if sys.version_info[0] >= 3: |
48 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX'] |
124 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX'] |
|
125 else: |
|
126 # deprecated in Python 3 |
|
127 DYLIB_SUFFIX = sysconfig.get_config_vars()['SO'] |
|
128 |
49 |
129 # Solaris Python packaging brain damage |
50 # Solaris Python packaging brain damage |
130 try: |
51 try: |
131 import hashlib |
52 import hashlib |
132 |
53 |
290 ) |
210 ) |
291 out, err = p.communicate() |
211 out, err = p.communicate() |
292 return p.returncode, out, err |
212 return p.returncode, out, err |
293 |
213 |
294 |
214 |
295 class hgcommand(object): |
215 class hgcommand: |
296 def __init__(self, cmd, env): |
216 def __init__(self, cmd, env): |
297 self.cmd = cmd |
217 self.cmd = cmd |
298 self.env = env |
218 self.env = env |
299 |
219 |
300 def run(self, args): |
220 def run(self, args): |
301 cmd = self.cmd + args |
221 cmd = self.cmd + args |
302 returncode, out, err = runcmd(cmd, self.env) |
222 returncode, out, err = runcmd(cmd, self.env) |
303 err = filterhgerr(err) |
223 err = filterhgerr(err) |
304 if err or returncode != 0: |
224 if err or returncode != 0: |
305 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr) |
225 print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr) |
306 printf(err, file=sys.stderr) |
226 print(err, file=sys.stderr) |
307 return b'' |
227 return b'' |
308 return out |
228 return out |
309 |
229 |
310 |
230 |
311 def filterhgerr(err): |
231 def filterhgerr(err): |
534 # TODO record it for proper rebuild upon changes |
454 # TODO record it for proper rebuild upon changes |
535 # (see mercurial/__modulepolicy__.py) |
455 # (see mercurial/__modulepolicy__.py) |
536 if hgrustext != 'cpython' and hgrustext is not None: |
456 if hgrustext != 'cpython' and hgrustext is not None: |
537 if hgrustext: |
457 if hgrustext: |
538 msg = 'unknown HGWITHRUSTEXT value: %s' % hgrustext |
458 msg = 'unknown HGWITHRUSTEXT value: %s' % hgrustext |
539 printf(msg, file=sys.stderr) |
459 print(msg, file=sys.stderr) |
540 hgrustext = None |
460 hgrustext = None |
541 self.rust = hgrustext is not None |
461 self.rust = hgrustext is not None |
542 self.no_rust = not self.rust |
462 self.no_rust = not self.rust |
543 return ret |
463 return ret |
544 |
464 |
808 ) |
728 ) |
809 pythonlib = dllbasename[:-4] |
729 pythonlib = dllbasename[:-4] |
810 |
730 |
811 # Copy the pythonXY.dll next to the binary so that it runs |
731 # Copy the pythonXY.dll next to the binary so that it runs |
812 # without tampering with PATH. |
732 # without tampering with PATH. |
813 fsdecode = lambda x: x |
|
814 if sys.version_info[0] >= 3: |
|
815 fsdecode = os.fsdecode |
|
816 dest = os.path.join( |
733 dest = os.path.join( |
817 os.path.dirname(self.hgtarget), |
734 os.path.dirname(self.hgtarget), |
818 fsdecode(dllbasename), |
735 os.fsdecode(dllbasename), |
819 ) |
736 ) |
820 |
737 |
821 if not os.path.exists(dest): |
738 if not os.path.exists(dest): |
822 shutil.copy(buf.value, dest) |
739 shutil.copy(buf.value, dest) |
823 |
740 |
824 # Also overwrite python3.dll so that hgext.git is usable. |
741 # Also overwrite python3.dll so that hgext.git is usable. |
825 # TODO: also handle the MSYS flavor |
742 # TODO: also handle the MSYS flavor |
826 if sys.version_info[0] >= 3: |
743 python_x = os.path.join( |
827 python_x = os.path.join( |
744 os.path.dirname(os.fsdecode(buf.value)), |
828 os.path.dirname(fsdecode(buf.value)), |
745 "python3.dll", |
829 "python3.dll", |
746 ) |
|
747 |
|
748 if os.path.exists(python_x): |
|
749 dest = os.path.join( |
|
750 os.path.dirname(self.hgtarget), |
|
751 os.path.basename(python_x), |
830 ) |
752 ) |
831 |
753 |
832 if os.path.exists(python_x): |
754 shutil.copy(python_x, dest) |
833 dest = os.path.join( |
|
834 os.path.dirname(self.hgtarget), |
|
835 os.path.basename(python_x), |
|
836 ) |
|
837 |
|
838 shutil.copy(python_x, dest) |
|
839 |
755 |
840 if not pythonlib: |
756 if not pythonlib: |
841 log.warn( |
757 log.warn( |
842 'could not determine Python DLL filename; assuming pythonXY' |
758 'could not determine Python DLL filename; assuming pythonXY' |
843 ) |
759 ) |
848 log.info('using %s as Python library name' % pythonlib) |
764 log.info('using %s as Python library name' % pythonlib) |
849 with open('mercurial/hgpythonlib.h', 'wb') as f: |
765 with open('mercurial/hgpythonlib.h', 'wb') as f: |
850 f.write(b'/* this file is autogenerated by setup.py */\n') |
766 f.write(b'/* this file is autogenerated by setup.py */\n') |
851 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib) |
767 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib) |
852 |
768 |
853 macros = None |
|
854 if sys.version_info[0] >= 3: |
|
855 macros = [('_UNICODE', None), ('UNICODE', None)] |
|
856 |
|
857 objects = self.compiler.compile( |
769 objects = self.compiler.compile( |
858 ['mercurial/exewrapper.c'], |
770 ['mercurial/exewrapper.c'], |
859 output_dir=self.build_temp, |
771 output_dir=self.build_temp, |
860 macros=macros, |
772 macros=[('_UNICODE', None), ('UNICODE', None)], |
861 ) |
773 ) |
862 self.compiler.link_executable( |
774 self.compiler.link_executable( |
863 objects, self.hgtarget, libraries=[], output_dir=self.build_temp |
775 objects, self.hgtarget, libraries=[], output_dir=self.build_temp |
864 ) |
776 ) |
865 if self.long_paths_support: |
777 if self.long_paths_support: |
1067 None, |
979 None, |
1068 'noop, present for eggless setuptools compat', |
980 'noop, present for eggless setuptools compat', |
1069 ), |
981 ), |
1070 ] |
982 ] |
1071 |
983 |
|
984 sub_commands = install.sub_commands + [ |
|
985 ('install_completion', lambda self: True) |
|
986 ] |
|
987 |
1072 # Also helps setuptools not be sad while we refuse to create eggs. |
988 # Also helps setuptools not be sad while we refuse to create eggs. |
1073 single_version_externally_managed = True |
989 single_version_externally_managed = True |
1074 |
990 |
1075 def get_sub_commands(self): |
991 def get_sub_commands(self): |
1076 # Screen out egg related commands to prevent egg generation. But allow |
992 # Screen out egg related commands to prevent egg generation. But allow |
1181 'not rewriting @LIBDIR@ in %s because install path ' |
1097 'not rewriting @LIBDIR@ in %s because install path ' |
1182 'not known' % outfile |
1098 'not known' % outfile |
1183 ) |
1099 ) |
1184 continue |
1100 continue |
1185 |
1101 |
1186 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape)) |
1102 data = data.replace(b'@LIBDIR@', libdir.encode('unicode_escape')) |
1187 with open(outfile, 'wb') as fp: |
1103 with open(outfile, 'wb') as fp: |
1188 fp.write(data) |
1104 fp.write(data) |
|
1105 |
|
1106 |
|
1107 class hginstallcompletion(Command): |
|
1108 description = 'Install shell completion' |
|
1109 |
|
1110 def initialize_options(self): |
|
1111 self.install_dir = None |
|
1112 self.outputs = [] |
|
1113 |
|
1114 def finalize_options(self): |
|
1115 self.set_undefined_options( |
|
1116 'install_data', ('install_dir', 'install_dir') |
|
1117 ) |
|
1118 |
|
1119 def get_outputs(self): |
|
1120 return self.outputs |
|
1121 |
|
1122 def run(self): |
|
1123 for src, dir_path, dest in ( |
|
1124 ( |
|
1125 'bash_completion', |
|
1126 ('share', 'bash-completion', 'completions'), |
|
1127 'hg', |
|
1128 ), |
|
1129 ('zsh_completion', ('share', 'zsh', 'site-functions'), '_hg'), |
|
1130 ): |
|
1131 dir = os.path.join(self.install_dir, *dir_path) |
|
1132 self.mkpath(dir) |
|
1133 |
|
1134 dest = os.path.join(dir, dest) |
|
1135 self.outputs.append(dest) |
|
1136 self.copy_file(os.path.join('contrib', src), dest) |
1189 |
1137 |
1190 |
1138 |
1191 # virtualenv installs custom distutils/__init__.py and |
1139 # virtualenv installs custom distutils/__init__.py and |
1192 # distutils/distutils.cfg files which essentially proxy back to the |
1140 # distutils/distutils.cfg files which essentially proxy back to the |
1193 # "real" distutils in the main Python install. The presence of this |
1141 # "real" distutils in the main Python install. The presence of this |
1276 'build_ext': hgbuildext, |
1224 'build_ext': hgbuildext, |
1277 'build_py': hgbuildpy, |
1225 'build_py': hgbuildpy, |
1278 'build_scripts': hgbuildscripts, |
1226 'build_scripts': hgbuildscripts, |
1279 'build_hgextindex': buildhgextindex, |
1227 'build_hgextindex': buildhgextindex, |
1280 'install': hginstall, |
1228 'install': hginstall, |
|
1229 'install_completion': hginstallcompletion, |
1281 'install_lib': hginstalllib, |
1230 'install_lib': hginstalllib, |
1282 'install_scripts': hginstallscripts, |
1231 'install_scripts': hginstallscripts, |
1283 'build_hgexe': buildhgexe, |
1232 'build_hgexe': buildhgexe, |
1284 } |
1233 } |
1285 |
1234 |
1322 'hgext.zeroconf', |
1271 'hgext.zeroconf', |
1323 'hgext3rd', |
1272 'hgext3rd', |
1324 'hgdemandimport', |
1273 'hgdemandimport', |
1325 ] |
1274 ] |
1326 |
1275 |
1327 # The pygit2 dependency dropped py2 support with the 1.0 release in Dec 2019. |
|
1328 # Prior releases do not build at all on Windows, because Visual Studio 2008 |
|
1329 # doesn't understand C 11. Older Linux releases are buggy. |
|
1330 if sys.version_info[0] == 2: |
|
1331 packages.remove('hgext.git') |
|
1332 |
|
1333 |
|
1334 for name in os.listdir(os.path.join('mercurial', 'templates')): |
1276 for name in os.listdir(os.path.join('mercurial', 'templates')): |
1335 if name != '__pycache__' and os.path.isdir( |
1277 if name != '__pycache__' and os.path.isdir( |
1336 os.path.join('mercurial', 'templates', name) |
1278 os.path.join('mercurial', 'templates', name) |
1337 ): |
1279 ): |
1338 packages.append('mercurial.templates.%s' % name) |
1280 packages.append('mercurial.templates.%s' % name) |
1339 |
|
1340 if sys.version_info[0] == 2: |
|
1341 packages.extend( |
|
1342 [ |
|
1343 'mercurial.thirdparty.concurrent', |
|
1344 'mercurial.thirdparty.concurrent.futures', |
|
1345 ] |
|
1346 ) |
|
1347 |
1281 |
1348 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ: |
1282 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ: |
1349 # py2exe can't cope with namespace packages very well, so we have to |
1283 # py2exe can't cope with namespace packages very well, so we have to |
1350 # install any hgext3rd.* extensions that we want in the final py2exe |
1284 # install any hgext3rd.* extensions that we want in the final py2exe |
1351 # image here. This is gross, but you gotta do what you gotta do. |
1285 # image here. This is gross, but you gotta do what you gotta do. |
1474 |
1408 |
1475 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir |
1409 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir |
1476 |
1410 |
1477 cargocmd = ['cargo', 'rustc', '--release'] |
1411 cargocmd = ['cargo', 'rustc', '--release'] |
1478 |
1412 |
1479 feature_flags = [] |
|
1480 |
|
1481 cargocmd.append('--no-default-features') |
|
1482 if sys.version_info[0] == 2: |
|
1483 feature_flags.append('python27') |
|
1484 elif sys.version_info[0] == 3: |
|
1485 feature_flags.append('python3') |
|
1486 |
|
1487 rust_features = env.get("HG_RUST_FEATURES") |
1413 rust_features = env.get("HG_RUST_FEATURES") |
1488 if rust_features: |
1414 if rust_features: |
1489 feature_flags.append(rust_features) |
1415 cargocmd.extend(('--features', rust_features)) |
1490 |
|
1491 cargocmd.extend(('--features', " ".join(feature_flags))) |
|
1492 |
1416 |
1493 cargocmd.append('--') |
1417 cargocmd.append('--') |
1494 if sys.platform == 'darwin': |
1418 if sys.platform == 'darwin': |
1495 cargocmd.extend( |
1419 cargocmd.extend( |
1496 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup") |
1420 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup") |
1497 ) |
1421 ) |
1498 try: |
1422 try: |
1499 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir) |
1423 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir) |
1500 except OSError as exc: |
1424 except FileNotFoundError: |
1501 if exc.errno == errno.ENOENT: |
1425 raise RustCompilationError("Cargo not found") |
1502 raise RustCompilationError("Cargo not found") |
1426 except PermissionError: |
1503 elif exc.errno == errno.EACCES: |
1427 raise RustCompilationError( |
1504 raise RustCompilationError( |
1428 "Cargo found, but permission to execute it is denied" |
1505 "Cargo found, but permission to execute it is denied" |
1429 ) |
1506 ) |
|
1507 else: |
|
1508 raise |
|
1509 except subprocess.CalledProcessError: |
1430 except subprocess.CalledProcessError: |
1510 raise RustCompilationError( |
1431 raise RustCompilationError( |
1511 "Cargo failed. Working directory: %r, " |
1432 "Cargo failed. Working directory: %r, " |
1512 "command: %r, environment: %r" |
1433 "command: %r, environment: %r" |
1513 % (self.rustsrcdir, cargocmd, env) |
1434 % (self.rustsrcdir, cargocmd, env) |
1761 setupversion = setupversion.split(r'+', 1)[0] |
1682 setupversion = setupversion.split(r'+', 1)[0] |
1762 |
1683 |
1763 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'): |
1684 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'): |
1764 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines() |
1685 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines() |
1765 if version: |
1686 if version: |
1766 version = version[0] |
1687 version = version[0].decode('utf-8') |
1767 if sys.version_info[0] == 3: |
|
1768 version = version.decode('utf-8') |
|
1769 xcode4 = version.startswith('Xcode') and StrictVersion( |
1688 xcode4 = version.startswith('Xcode') and StrictVersion( |
1770 version.split()[1] |
1689 version.split()[1] |
1771 ) >= StrictVersion('4.0') |
1690 ) >= StrictVersion('4.0') |
1772 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None |
1691 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None |
1773 else: |
1692 else: |