Blame 00251-change-user-install-location.patch

acc1ca2
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
38f9dd1
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
47935cf
Date: Mon, 15 Feb 2021 12:19:27 +0100
29530ba
Subject: [PATCH] 00251: Change user install location
d5c558e
MIME-Version: 1.0
d5c558e
Content-Type: text/plain; charset=UTF-8
d5c558e
Content-Transfer-Encoding: 8bit
285f554
38f9dd1
Set values of base and platbase in sysconfig from /usr
38f9dd1
to /usr/local when RPM build is not detected
38f9dd1
to make pip and similar tools install into separate location.
47935cf
38f9dd1
Set values of prefix and exec_prefix in distutils install command
38f9dd1
to /usr/local if executable is /usr/bin/python* and RPM build
38f9dd1
is not detected to make distutils and pypa/distutils install into separate location.
285f554
285f554
Fedora Change: https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
38f9dd1
Downstream only.
47935cf
38f9dd1
We've tried to rework in Fedora 36/Python 3.10 to follow https://bugs.python.org/issue43976
38f9dd1
but we have identified serious problems with that approach,
38f9dd1
see https://bugzilla.redhat.com/2026979 or https://bugzilla.redhat.com/2097183
47935cf
38f9dd1
pypa/distutils integration: https://github.com/pypa/distutils/pull/70
47935cf
47935cf
Co-authored-by: Petr Viktorin <encukou@gmail.com>
47935cf
Co-authored-by: Miro Hrončok <miro@hroncok.cz>
47935cf
Co-authored-by: Michal Cyprian <m.cyprian@gmail.com>
d5c558e
Co-authored-by: Lumír Balhar <frenzy.madness@gmail.com>
285f554
---
38f9dd1
 Lib/distutils/command/install.py |  8 +++--
38f9dd1
 Lib/site.py                      |  9 +++++-
38f9dd1
 Lib/sysconfig.py                 | 53 +++++++++++++++++++++++++++++++-
38f9dd1
 Lib/test/test_sysconfig.py       | 17 ++++++++--
38f9dd1
 4 files changed, 81 insertions(+), 6 deletions(-)
47935cf
38f9dd1
diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py
38f9dd1
index 01d5331a63..79f70f0de4 100644
38f9dd1
--- a/Lib/distutils/command/install.py
38f9dd1
+++ b/Lib/distutils/command/install.py
38f9dd1
@@ -159,6 +159,8 @@ class install(Command):
38f9dd1
 
38f9dd1
     negative_opt = {'no-compile' : 'compile'}
38f9dd1
 
38f9dd1
+    # Allow Fedora to add components to the prefix
38f9dd1
+    _prefix_addition = getattr(sysconfig, '_prefix_addition', '')
38f9dd1
 
38f9dd1
     def initialize_options(self):
38f9dd1
         """Initializes options."""
38f9dd1
@@ -441,8 +443,10 @@ def finalize_unix(self):
38f9dd1
                     raise DistutilsOptionError(
38f9dd1
                           "must not supply exec-prefix without prefix")
38f9dd1
 
38f9dd1
-                self.prefix = os.path.normpath(sys.prefix)
38f9dd1
-                self.exec_prefix = os.path.normpath(sys.exec_prefix)
38f9dd1
+                self.prefix = (
38f9dd1
+                    os.path.normpath(sys.prefix) + self._prefix_addition)
38f9dd1
+                self.exec_prefix = (
38f9dd1
+                    os.path.normpath(sys.exec_prefix) + self._prefix_addition)
38f9dd1
 
38f9dd1
             else:
38f9dd1
                 if self.exec_prefix is None:
332b947
diff --git a/Lib/site.py b/Lib/site.py
9f58744
index 939893eb5e..d1316c3355 100644
332b947
--- a/Lib/site.py
332b947
+++ b/Lib/site.py
9f58744
@@ -380,8 +380,15 @@ def getsitepackages(prefixes=None):
332b947
     return sitepackages
285f554
 
332b947
 def addsitepackages(known_paths, prefixes=None):
332b947
-    """Add site-packages to sys.path"""
Michal Cyprian 08ffd08
+    """Add site-packages to sys.path
332b947
+
Michal Cyprian 08ffd08
+    '/usr/local' is included in PREFIXES if RPM build is not detected
Michal Cyprian 08ffd08
+    to make packages installed into this location visible.
332b947
+
332b947
+    """
d3f7caa
     _trace("Processing global site-packages")
Michal Cyprian 08ffd08
+    if ENABLE_USER_SITE and 'RPM_BUILD_ROOT' not in os.environ:
332b947
+        PREFIXES.insert(0, "/usr/local")
332b947
     for sitedir in getsitepackages(prefixes):
332b947
         if os.path.isdir(sitedir):
332b947
             addsitedir(sitedir, known_paths)
47935cf
diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py
38f9dd1
index daf9f00006..10368c92a7 100644
47935cf
--- a/Lib/sysconfig.py
47935cf
+++ b/Lib/sysconfig.py
38f9dd1
@@ -58,6 +58,16 @@
47935cf
         },
47935cf
     }
47935cf
 
38f9dd1
+# For a brief period of time in the Fedora 36 life cycle,
38f9dd1
+# this installation scheme existed and was documented in the release notes.
38f9dd1
+# For backwards compatibility, we keep it here (at least on 3.10 and 3.11).
47935cf
+_INSTALL_SCHEMES['rpm_prefix'] = _INSTALL_SCHEMES['posix_prefix']
d5c558e
+# Virtualenv >= 20.10.0 favors the "venv" scheme over the defaults when creating virtual environments.
d5c558e
+# See: https://github.com/pypa/virtualenv/commit/8da79db86d8a5c74d03667a40e64ff832076445e
d5c558e
+# See: https://bugs.python.org/issue45413
38f9dd1
+# "venv" should be the same as the posix_prefix for us,
d5c558e
+# so new virtual environments aren't created with paths like venv/local/bin/python.
d5c558e
+_INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['posix_prefix']
38f9dd1
 
38f9dd1
 # NOTE: site.py has copy of this function.
38f9dd1
 # Sync it when modify this function.
38f9dd1
@@ -117,6 +127,19 @@ def joinuser(*args):
38f9dd1
             },
38f9dd1
     }
38f9dd1
 
38f9dd1
+# This is used by distutils.command.install in the stdlib
38f9dd1
+# as well as pypa/distutils (e.g. bundled in setuptools).
38f9dd1
+# The self.prefix value is set to sys.prefix + /local/
38f9dd1
+# if neither RPM build nor virtual environment is
38f9dd1
+# detected to make distutils install packages
38f9dd1
+# into the separate location.
38f9dd1
+# https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
47935cf
+if (not (hasattr(sys, 'real_prefix') or
47935cf
+    sys.prefix != sys.base_prefix) and
47935cf
+    'RPM_BUILD_ROOT' not in os.environ):
38f9dd1
+    _prefix_addition = '/local'
38f9dd1
+
38f9dd1
+
38f9dd1
 _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
38f9dd1
                 'scripts', 'data')
47935cf
 
38f9dd1
@@ -211,11 +234,39 @@ def _extend_dict(target_dict, other_dict):
38f9dd1
         target_dict[key] = value
38f9dd1
 
38f9dd1
 
38f9dd1
+_CONFIG_VARS_LOCAL = None
38f9dd1
+
38f9dd1
+
38f9dd1
+def _config_vars_local():
38f9dd1
+    # This function returns the config vars with prefixes amended to /usr/local
38f9dd1
+    # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
38f9dd1
+    global _CONFIG_VARS_LOCAL
38f9dd1
+    if _CONFIG_VARS_LOCAL is None:
38f9dd1
+        _CONFIG_VARS_LOCAL = dict(get_config_vars())
38f9dd1
+        _CONFIG_VARS_LOCAL['base'] = '/usr/local'
38f9dd1
+        _CONFIG_VARS_LOCAL['platbase'] = '/usr/local'
38f9dd1
+    return _CONFIG_VARS_LOCAL
38f9dd1
+
38f9dd1
+
38f9dd1
 def _expand_vars(scheme, vars):
38f9dd1
     res = {}
38f9dd1
     if vars is None:
38f9dd1
         vars = {}
38f9dd1
-    _extend_dict(vars, get_config_vars())
38f9dd1
+
38f9dd1
+    # when we are not in a virtual environment or an RPM build
38f9dd1
+    # we change '/usr' to '/usr/local'
38f9dd1
+    # to avoid surprises, we explicitly check for the /usr/ prefix
38f9dd1
+    # Python virtual environments have different prefixes
38f9dd1
+    # we only do this for posix_prefix, not to mangle the venv scheme
38f9dd1
+    # posix_prefix is used by sudo pip install
38f9dd1
+    # we only change the defaults here, so explicit --prefix will take precedence
38f9dd1
+    # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
38f9dd1
+    if (scheme == 'posix_prefix' and
38f9dd1
+        _PREFIX == '/usr' and
38f9dd1
+        'RPM_BUILD_ROOT' not in os.environ):
38f9dd1
+            _extend_dict(vars, _config_vars_local())
38f9dd1
+    else:
38f9dd1
+        _extend_dict(vars, get_config_vars())
38f9dd1
 
38f9dd1
     for key, value in _INSTALL_SCHEMES[scheme].items():
38f9dd1
         if os.name in ('posix', 'nt'):
47935cf
diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
38f9dd1
index 5ee9839c04..16e92ca86f 100644
47935cf
--- a/Lib/test/test_sysconfig.py
47935cf
+++ b/Lib/test/test_sysconfig.py
38f9dd1
@@ -105,8 +105,19 @@ def test_get_path(self):
38f9dd1
         for scheme in _INSTALL_SCHEMES:
38f9dd1
             for name in _INSTALL_SCHEMES[scheme]:
38f9dd1
                 expected = _INSTALL_SCHEMES[scheme][name].format(**config_vars)
38f9dd1
+                tested = get_path(name, scheme)
38f9dd1
+                # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
38f9dd1
+                if tested.startswith('/usr/local'):
38f9dd1
+                    # /usr/local should only be used in posix_prefix
38f9dd1
+                    self.assertEqual(scheme, 'posix_prefix')
38f9dd1
+                    # Fedora CI runs tests for venv and virtualenv that check for other prefixes
38f9dd1
+                    self.assertEqual(sys.prefix, '/usr')
38f9dd1
+                    # When building the RPM of Python, %check runs this with RPM_BUILD_ROOT set
38f9dd1
+                    # Fedora CI runs this with RPM_BUILD_ROOT unset
38f9dd1
+                    self.assertNotIn('RPM_BUILD_ROOT', os.environ)
38f9dd1
+                    tested = tested.replace('/usr/local', '/usr')
38f9dd1
                 self.assertEqual(
38f9dd1
-                    os.path.normpath(get_path(name, scheme)),
38f9dd1
+                    os.path.normpath(tested),
38f9dd1
                     os.path.normpath(expected),
38f9dd1
                 )
38f9dd1
 
38f9dd1
@@ -263,7 +274,7 @@ def test_get_config_h_filename(self):
47935cf
         self.assertTrue(os.path.isfile(config_h), config_h)
47935cf
 
47935cf
     def test_get_scheme_names(self):
47935cf
-        wanted = ['nt', 'posix_home', 'posix_prefix']
d5c558e
+        wanted = ['nt', 'posix_home', 'posix_prefix', 'rpm_prefix', 'venv']
47935cf
         if HAS_USER_BASE:
47935cf
             wanted.extend(['nt_user', 'osx_framework_user', 'posix_user'])
47935cf
         self.assertEqual(get_scheme_names(), tuple(sorted(wanted)))
38f9dd1
@@ -274,6 +285,8 @@ def test_symlink(self): # Issue 7880
47935cf
             cmd = "-c", "import sysconfig; print(sysconfig.get_platform())"
47935cf
             self.assertEqual(py.call_real(*cmd), py.call_link(*cmd))
47935cf
 
47935cf
+    @unittest.skipIf('RPM_BUILD_ROOT' not in os.environ,
47935cf
+                     "Test doesn't expect Fedora's paths")
47935cf
     def test_user_similar(self):
47935cf
         # Issue #8759: make sure the posix scheme for the users
47935cf
         # is similar to the global posix_prefix one