setup.py
branchstable
changeset 49366 288de6f5d724
parent 49310 050dc8730858
child 49394 5cf73de964e1
equal deleted inserted replaced
49364:e8ea403b1c46 49366:288de6f5d724
     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 
   172         )
    93         )
   173 
    94 
   174 ispypy = "PyPy" in sys.version
    95 ispypy = "PyPy" in sys.version
   175 
    96 
   176 import ctypes
    97 import ctypes
   177 import errno
       
   178 import stat, subprocess, time
    98 import stat, subprocess, time
   179 import re
    99 import re
   180 import shutil
   100 import shutil
   181 import tempfile
   101 import tempfile
   182 
   102 
   274 
   194 
   275 # py2exe needs to be installed to work
   195 # py2exe needs to be installed to work
   276 try:
   196 try:
   277     import py2exe
   197     import py2exe
   278 
   198 
   279     py2exe.Distribution  # silence unused import warning
   199     py2exe.patch_distutils()
   280     py2exeloaded = True
   200     py2exeloaded = True
   281     # import py2exe's patched Distribution class
   201     # import py2exe's patched Distribution class
   282     from distutils.core import Distribution
   202     from distutils.core import Distribution
   283 except ImportError:
   203 except ImportError:
   284     py2exeloaded = False
   204     py2exeloaded = False
   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)
  1638     cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
  1559     cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
  1639 except ImportError:
  1560 except ImportError:
  1640     # the cygwinccompiler package is not available on some Python
  1561     # the cygwinccompiler package is not available on some Python
  1641     # distributions like the ones from the optware project for Synology
  1562     # distributions like the ones from the optware project for Synology
  1642     # DiskStation boxes
  1563     # DiskStation boxes
  1643     class HackedMingw32CCompiler(object):
  1564     class HackedMingw32CCompiler:
  1644         pass
  1565         pass
  1645 
  1566 
  1646 
  1567 
  1647 if os.name == 'nt':
  1568 if os.name == 'nt':
  1648     # Allow compiler/linker flags to be added to Visual Studio builds.  Passing
  1569     # Allow compiler/linker flags to be added to Visual Studio builds.  Passing
  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: