mkvenv: always pass locally-installed packages to pip
Let pip decide whether a new version should be installed or the current one is okay. This ensures that the virtual environment is updated (either upgraded or downgraded) whenever a new version of a package is requested. The hardest part here is figuring out if a package is installed in the venv (which also has to be done twice to account for the presence of either setuptools in Python <3.8, or importlib in Python >=3.8). Suggested-by: Peter Maydell <peter.maydell@linaro.org> Cc: John Snow <jsnow@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
e8e4298fea
commit
47a90a51a9
@ -553,6 +553,74 @@ def pkgname_from_depspec(dep_spec: str) -> str:
|
|||||||
return match.group(0)
|
return match.group(0)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_path_importlib(package: str) -> Optional[str]:
|
||||||
|
# pylint: disable=import-outside-toplevel
|
||||||
|
# pylint: disable=no-name-in-module
|
||||||
|
# pylint: disable=import-error
|
||||||
|
try:
|
||||||
|
# First preference: Python 3.8+ stdlib
|
||||||
|
from importlib.metadata import ( # type: ignore
|
||||||
|
PackageNotFoundError,
|
||||||
|
distribution,
|
||||||
|
)
|
||||||
|
except ImportError as exc:
|
||||||
|
logger.debug("%s", str(exc))
|
||||||
|
# Second preference: Commonly available PyPI backport
|
||||||
|
from importlib_metadata import ( # type: ignore
|
||||||
|
PackageNotFoundError,
|
||||||
|
distribution,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return str(distribution(package).locate_file("."))
|
||||||
|
except PackageNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_path_pkg_resources(package: str) -> Optional[str]:
|
||||||
|
# pylint: disable=import-outside-toplevel
|
||||||
|
# Bundled with setuptools; has a good chance of being available.
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
|
try:
|
||||||
|
return str(pkg_resources.get_distribution(package).location)
|
||||||
|
except pkg_resources.DistributionNotFound:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_path(package: str) -> Optional[str]:
|
||||||
|
try:
|
||||||
|
return _get_path_importlib(package)
|
||||||
|
except ImportError as exc:
|
||||||
|
logger.debug("%s", str(exc))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return _get_path_pkg_resources(package)
|
||||||
|
except ImportError as exc:
|
||||||
|
logger.debug("%s", str(exc))
|
||||||
|
raise Ouch(
|
||||||
|
"Neither importlib.metadata nor pkg_resources found. "
|
||||||
|
"Use Python 3.8+, or install importlib-metadata or setuptools."
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
|
def _path_is_prefix(prefix: Optional[str], path: str) -> bool:
|
||||||
|
try:
|
||||||
|
return (
|
||||||
|
prefix is not None and os.path.commonpath([prefix, path]) == prefix
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _is_system_package(package: str) -> bool:
|
||||||
|
path = _get_path(package)
|
||||||
|
return path is not None and not (
|
||||||
|
_path_is_prefix(sysconfig.get_path("purelib"), path)
|
||||||
|
or _path_is_prefix(sysconfig.get_path("platlib"), path)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_version_importlib(package: str) -> Optional[str]:
|
def _get_version_importlib(package: str) -> Optional[str]:
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
# pylint: disable=no-name-in-module
|
# pylint: disable=no-name-in-module
|
||||||
@ -741,8 +809,12 @@ def _do_ensure(
|
|||||||
for spec in dep_specs:
|
for spec in dep_specs:
|
||||||
matcher = distlib.version.LegacyMatcher(spec)
|
matcher = distlib.version.LegacyMatcher(spec)
|
||||||
ver = _get_version(matcher.name)
|
ver = _get_version(matcher.name)
|
||||||
if ver is None or not matcher.match(
|
if (
|
||||||
distlib.version.LegacyVersion(ver)
|
ver is None
|
||||||
|
# Always pass installed package to pip, so that they can be
|
||||||
|
# updated if the requested version changes
|
||||||
|
or not _is_system_package(matcher.name)
|
||||||
|
or not matcher.match(distlib.version.LegacyVersion(ver))
|
||||||
):
|
):
|
||||||
absent.append(spec)
|
absent.append(spec)
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user