summaryrefslogtreecommitdiff
path: root/setuptools/_distutils/command/install.py
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/_distutils/command/install.py')
-rw-r--r--setuptools/_distutils/command/install.py237
1 files changed, 167 insertions, 70 deletions
diff --git a/setuptools/_distutils/command/install.py b/setuptools/_distutils/command/install.py
index 866e2d59..511938f4 100644
--- a/setuptools/_distutils/command/install.py
+++ b/setuptools/_distutils/command/install.py
@@ -4,6 +4,9 @@ Implements the Distutils 'install' command."""
import sys
import os
+import contextlib
+import sysconfig
+import itertools
from distutils import log
from distutils.core import Command
@@ -14,68 +17,69 @@ from distutils.file_util import write_file
from distutils.util import convert_path, subst_vars, change_root
from distutils.util import get_platform
from distutils.errors import DistutilsOptionError
+from .. import _collections
from site import USER_BASE
from site import USER_SITE
HAS_USER_SITE = True
WINDOWS_SCHEME = {
- 'purelib': '$base/Lib/site-packages',
- 'platlib': '$base/Lib/site-packages',
- 'headers': '$base/Include/$dist_name',
- 'scripts': '$base/Scripts',
- 'data' : '$base',
+ 'purelib': '{base}/Lib/site-packages',
+ 'platlib': '{base}/Lib/site-packages',
+ 'headers': '{base}/Include/{dist_name}',
+ 'scripts': '{base}/Scripts',
+ 'data' : '{base}',
}
INSTALL_SCHEMES = {
- 'unix_prefix': {
- 'purelib': '$base/lib/python$py_version_short/site-packages',
- 'platlib': '$platbase/$platlibdir/python$py_version_short/site-packages',
- 'headers': '$base/include/python$py_version_short$abiflags/$dist_name',
- 'scripts': '$base/bin',
- 'data' : '$base',
+ 'posix_prefix': {
+ 'purelib': '{base}/lib/{implementation_lower}{py_version_short}/site-packages',
+ 'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}/site-packages',
+ 'headers': '{base}/include/{implementation_lower}{py_version_short}{abiflags}/{dist_name}',
+ 'scripts': '{base}/bin',
+ 'data' : '{base}',
},
- 'unix_home': {
- 'purelib': '$base/lib/python',
- 'platlib': '$base/$platlibdir/python',
- 'headers': '$base/include/python/$dist_name',
- 'scripts': '$base/bin',
- 'data' : '$base',
+ 'posix_home': {
+ 'purelib': '{base}/lib/{implementation_lower}',
+ 'platlib': '{base}/{platlibdir}/{implementation_lower}',
+ 'headers': '{base}/include/{implementation_lower}/{dist_name}',
+ 'scripts': '{base}/bin',
+ 'data' : '{base}',
},
'nt': WINDOWS_SCHEME,
'pypy': {
- 'purelib': '$base/site-packages',
- 'platlib': '$base/site-packages',
- 'headers': '$base/include/$dist_name',
- 'scripts': '$base/bin',
- 'data' : '$base',
+ 'purelib': '{base}/site-packages',
+ 'platlib': '{base}/site-packages',
+ 'headers': '{base}/include/{dist_name}',
+ 'scripts': '{base}/bin',
+ 'data' : '{base}',
},
'pypy_nt': {
- 'purelib': '$base/site-packages',
- 'platlib': '$base/site-packages',
- 'headers': '$base/include/$dist_name',
- 'scripts': '$base/Scripts',
- 'data' : '$base',
+ 'purelib': '{base}/site-packages',
+ 'platlib': '{base}/site-packages',
+ 'headers': '{base}/include/{dist_name}',
+ 'scripts': '{base}/Scripts',
+ 'data' : '{base}',
},
}
# user site schemes
if HAS_USER_SITE:
INSTALL_SCHEMES['nt_user'] = {
- 'purelib': '$usersite',
- 'platlib': '$usersite',
- 'headers': '$userbase/Python$py_version_nodot/Include/$dist_name',
- 'scripts': '$userbase/Python$py_version_nodot/Scripts',
- 'data' : '$userbase',
+ 'purelib': '{usersite}',
+ 'platlib': '{usersite}',
+ 'headers': '{userbase}/{implementation}{py_version_nodot}/Include/{dist_name}',
+ 'scripts': '{userbase}/{implementation}{py_version_nodot}/Scripts',
+ 'data' : '{userbase}',
}
- INSTALL_SCHEMES['unix_user'] = {
- 'purelib': '$usersite',
- 'platlib': '$usersite',
+ INSTALL_SCHEMES['posix_user'] = {
+ 'purelib': '{usersite}',
+ 'platlib': '{usersite}',
'headers':
- '$userbase/include/python$py_version_short$abiflags/$dist_name',
- 'scripts': '$userbase/bin',
- 'data' : '$userbase',
+ '{userbase}/include/{implementation_lower}{py_version_short}{abiflags}/{dist_name}',
+ 'scripts': '{userbase}/bin',
+ 'data' : '{userbase}',
}
# The keys to an installation scheme; if any new types of files are to be
@@ -84,6 +88,96 @@ if HAS_USER_SITE:
SCHEME_KEYS = ('purelib', 'platlib', 'headers', 'scripts', 'data')
+def _load_sysconfig_schemes():
+ with contextlib.suppress(AttributeError):
+ return {
+ scheme: sysconfig.get_paths(scheme, expand=False)
+ for scheme in sysconfig.get_scheme_names()
+ }
+
+
+def _load_schemes():
+ """
+ Extend default schemes with schemes from sysconfig.
+ """
+
+ sysconfig_schemes = _load_sysconfig_schemes() or {}
+
+ return {
+ scheme: {
+ **INSTALL_SCHEMES.get(scheme, {}),
+ **sysconfig_schemes.get(scheme, {}),
+ }
+ for scheme in set(itertools.chain(INSTALL_SCHEMES, sysconfig_schemes))
+ }
+
+
+def _get_implementation():
+ if hasattr(sys, 'pypy_version_info'):
+ return 'PyPy'
+ else:
+ return 'Python'
+
+
+def _select_scheme(ob, name):
+ scheme = _inject_headers(name, _load_scheme(_resolve_scheme(name)))
+ vars(ob).update(_remove_set(ob, _scheme_attrs(scheme)))
+
+
+def _remove_set(ob, attrs):
+ """
+ Include only attrs that are None in ob.
+ """
+ return {
+ key: value
+ for key, value in attrs.items()
+ if getattr(ob, key) is None
+ }
+
+
+def _resolve_scheme(name):
+ os_name, sep, key = name.partition('_')
+ try:
+ resolved = sysconfig.get_preferred_scheme(key)
+ except Exception:
+ resolved = _pypy_hack(name)
+ return resolved
+
+
+def _load_scheme(name):
+ return _load_schemes()[name]
+
+
+def _inject_headers(name, scheme):
+ """
+ Given a scheme name and the resolved scheme,
+ if the scheme does not include headers, resolve
+ the fallback scheme for the name and use headers
+ from it. pypa/distutils#88
+ """
+ # Bypass the preferred scheme, which may not
+ # have defined headers.
+ fallback = _load_scheme(_pypy_hack(name))
+ scheme.setdefault('headers', fallback['headers'])
+ return scheme
+
+
+def _scheme_attrs(scheme):
+ """Resolve install directories by applying the install schemes."""
+ return {
+ f'install_{key}': scheme[key]
+ for key in SCHEME_KEYS
+ }
+
+
+def _pypy_hack(name):
+ PY37 = sys.version_info < (3, 8)
+ old_pypy = hasattr(sys, 'pypy_version_info') and PY37
+ prefix = not name.endswith(('_user', '_home'))
+ pypy_name = 'pypy' + '_nt' * (os.name == 'nt')
+ return pypy_name if old_pypy and prefix else name
+
+
class install(Command):
description = "install everything from build directory"
@@ -278,7 +372,7 @@ class install(Command):
# input a heady brew of prefix, exec_prefix, home, install_base,
# install_platbase, user-supplied versions of
# install_{purelib,platlib,lib,scripts,data,...}, and the
- # INSTALL_SCHEME dictionary above. Phew!
+ # install schemes. Phew!
self.dump_dirs("pre-finalize_{unix,other}")
@@ -301,7 +395,8 @@ class install(Command):
except AttributeError:
# sys.abiflags may not be defined on all platforms.
abiflags = ''
- self.config_vars = {'dist_name': self.distribution.get_name(),
+ local_vars = {
+ 'dist_name': self.distribution.get_name(),
'dist_version': self.distribution.get_version(),
'dist_fullname': self.distribution.get_fullname(),
'py_version': py_version,
@@ -313,11 +408,16 @@ class install(Command):
'exec_prefix': exec_prefix,
'abiflags': abiflags,
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
+ 'implementation_lower': _get_implementation().lower(),
+ 'implementation': _get_implementation(),
}
if HAS_USER_SITE:
- self.config_vars['userbase'] = self.install_userbase
- self.config_vars['usersite'] = self.install_usersite
+ local_vars['userbase'] = self.install_userbase
+ local_vars['usersite'] = self.install_usersite
+
+ self.config_vars = _collections.DictStack(
+ [sysconfig.get_config_vars(), local_vars])
self.expand_basedirs()
@@ -325,13 +425,13 @@ class install(Command):
# Now define config vars for the base directories so we can expand
# everything else.
- self.config_vars['base'] = self.install_base
- self.config_vars['platbase'] = self.install_platbase
+ local_vars['base'] = self.install_base
+ local_vars['platbase'] = self.install_platbase
if DEBUG:
from pprint import pprint
print("config vars:")
- pprint(self.config_vars)
+ pprint(dict(self.config_vars))
# Expand "~" and configuration variables in the installation
# directories.
@@ -407,12 +507,17 @@ class install(Command):
def finalize_unix(self):
"""Finalizes options for posix platforms."""
if self.install_base is not None or self.install_platbase is not None:
- if ((self.install_lib is None and
- self.install_purelib is None and
- self.install_platlib is None) or
+ incomplete_scheme = (
+ (
+ self.install_lib is None and
+ self.install_purelib is None and
+ self.install_platlib is None
+ ) or
self.install_headers is None or
self.install_scripts is None or
- self.install_data is None):
+ self.install_data is None
+ )
+ if incomplete_scheme:
raise DistutilsOptionError(
"install-base or install-platbase supplied, but "
"installation scheme is incomplete")
@@ -423,18 +528,23 @@ class install(Command):
raise DistutilsPlatformError(
"User base directory is not specified")
self.install_base = self.install_platbase = self.install_userbase
- self.select_scheme("unix_user")
+ self.select_scheme("posix_user")
elif self.home is not None:
self.install_base = self.install_platbase = self.home
- self.select_scheme("unix_home")
+ self.select_scheme("posix_home")
else:
if self.prefix is None:
if self.exec_prefix is not None:
raise DistutilsOptionError(
"must not supply exec-prefix without prefix")
- self.prefix = os.path.normpath(sys.prefix)
- self.exec_prefix = os.path.normpath(sys.exec_prefix)
+ # Allow Fedora to add components to the prefix
+ _prefix_addition = getattr(sysconfig, '_prefix_addition', "")
+
+ self.prefix = (
+ os.path.normpath(sys.prefix) + _prefix_addition)
+ self.exec_prefix = (
+ os.path.normpath(sys.exec_prefix) + _prefix_addition)
else:
if self.exec_prefix is None:
@@ -442,7 +552,7 @@ class install(Command):
self.install_base = self.prefix
self.install_platbase = self.exec_prefix
- self.select_scheme("unix_prefix")
+ self.select_scheme("posix_prefix")
def finalize_other(self):
"""Finalizes options for non-posix platforms"""
@@ -454,7 +564,7 @@ class install(Command):
self.select_scheme(os.name + "_user")
elif self.home is not None:
self.install_base = self.install_platbase = self.home
- self.select_scheme("unix_home")
+ self.select_scheme("posix_home")
else:
if self.prefix is None:
self.prefix = os.path.normpath(sys.prefix)
@@ -467,20 +577,7 @@ class install(Command):
"I don't know how to install stuff on '%s'" % os.name)
def select_scheme(self, name):
- """Sets the install directories by applying the install schemes."""
- # it's the caller's problem if they supply a bad name!
- if (hasattr(sys, 'pypy_version_info') and
- sys.version_info < (3, 8) and
- not name.endswith(('_user', '_home'))):
- if os.name == 'nt':
- name = 'pypy_nt'
- else:
- name = 'pypy'
- scheme = INSTALL_SCHEMES[name]
- for key in SCHEME_KEYS:
- attrname = 'install_' + key
- if getattr(self, attrname) is None:
- setattr(self, attrname, scheme[key])
+ _select_scheme(self, name)
def _expand_attrs(self, attrs):
for attr in attrs:
@@ -554,7 +651,7 @@ class install(Command):
return
home = convert_path(os.path.expanduser("~"))
for name, path in self.config_vars.items():
- if path.startswith(home) and not os.path.isdir(path):
+ if str(path).startswith(home) and not os.path.isdir(path):
self.debug_print("os.makedirs('%s', 0o700)" % path)
os.makedirs(path, 0o700)