bootstrap: handle a new edge case of binary python packages with missing python-venv (#47094)

relevant for clingo installed without gcc-runtime and python-venv, which
is done for good reasons.
This commit is contained in:
Harmen Stoppels 2024-10-21 18:46:13 +02:00 committed by GitHub
parent 4187c57250
commit 19ad29a690
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 14 deletions

View File

@ -2562,7 +2562,13 @@ def _ensure_common_prefix(tar: tarfile.TarFile) -> str:
return pkg_prefix return pkg_prefix
def install_root_node(spec, unsigned=False, force=False, sha256=None): def install_root_node(
spec: spack.spec.Spec,
unsigned=False,
force: bool = False,
sha256: Optional[str] = None,
allow_missing: bool = False,
) -> None:
"""Install the root node of a concrete spec from a buildcache. """Install the root node of a concrete spec from a buildcache.
Checking the sha256 sum of a node before installation is usually needed only Checking the sha256 sum of a node before installation is usually needed only
@ -2571,11 +2577,10 @@ def install_root_node(spec, unsigned=False, force=False, sha256=None):
Args: Args:
spec: spec to be installed (note that only the root node will be installed) spec: spec to be installed (note that only the root node will be installed)
unsigned (bool): if True allows installing unsigned binaries unsigned: if True allows installing unsigned binaries
force (bool): force installation if the spec is already present in the force: force installation if the spec is already present in the local store
local store sha256: optional sha256 of the binary package, to be checked before installation
sha256 (str): optional sha256 of the binary package, to be checked allow_missing: when true, allows installing a node with missing dependencies
before installation
""" """
# Early termination # Early termination
if spec.external or spec.virtual: if spec.external or spec.virtual:
@ -2613,7 +2618,7 @@ def install_root_node(spec, unsigned=False, force=False, sha256=None):
spec, spack.store.STORE.layout.spec_file_path(spec) spec, spack.store.STORE.layout.spec_file_path(spec)
) )
spack.hooks.post_install(spec, False) spack.hooks.post_install(spec, False)
spack.store.STORE.db.add(spec) spack.store.STORE.db.add(spec, allow_missing=allow_missing)
def install_single_spec(spec, unsigned=False, force=False): def install_single_spec(spec, unsigned=False, force=False):

View File

@ -4,6 +4,7 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
"""Common basic functions used through the spack.bootstrap package""" """Common basic functions used through the spack.bootstrap package"""
import fnmatch import fnmatch
import glob
import importlib import importlib
import os.path import os.path
import re import re
@ -60,10 +61,19 @@ def _try_import_from_store(
python, *_ = candidate_spec.dependencies("python-venv") python, *_ = candidate_spec.dependencies("python-venv")
else: else:
python, *_ = candidate_spec.dependencies("python") python, *_ = candidate_spec.dependencies("python")
# if python is installed, ask it for the layout
if python.installed:
module_paths = [ module_paths = [
os.path.join(candidate_spec.prefix, python.package.purelib), os.path.join(candidate_spec.prefix, python.package.purelib),
os.path.join(candidate_spec.prefix, python.package.platlib), os.path.join(candidate_spec.prefix, python.package.platlib),
] ]
# otherwise search for the site-packages directory
# (clingo from binaries with truncated python-venv runtime)
else:
module_paths = glob.glob(
os.path.join(candidate_spec.prefix, "lib", "python*", "site-packages")
)
path_before = list(sys.path) path_before = list(sys.path)
# NOTE: try module_paths first and last, last allows an existing version in path # NOTE: try module_paths first and last, last allows an existing version in path

View File

@ -175,7 +175,15 @@ def _install_by_hash(
query = spack.binary_distribution.BinaryCacheQuery(all_architectures=True) query = spack.binary_distribution.BinaryCacheQuery(all_architectures=True)
for match in spack.store.find([f"/{pkg_hash}"], multiple=False, query_fn=query): for match in spack.store.find([f"/{pkg_hash}"], multiple=False, query_fn=query):
spack.binary_distribution.install_root_node( spack.binary_distribution.install_root_node(
match, unsigned=True, force=True, sha256=pkg_sha256 # allow_missing is true since when bootstrapping clingo we truncate runtime
# deps such as gcc-runtime, since we link libstdc++ statically, and the other
# further runtime deps are loaded by the Python interpreter. This just silences
# warnings about missing dependencies.
match,
unsigned=True,
force=True,
sha256=pkg_sha256,
allow_missing=True,
) )
def _install_and_test( def _install_and_test(

View File

@ -1245,7 +1245,7 @@ def _add(
self._data[key].explicit = explicit self._data[key].explicit = explicit
@_autospec @_autospec
def add(self, spec: "spack.spec.Spec", *, explicit: bool = False) -> None: def add(self, spec: "spack.spec.Spec", *, explicit: bool = False, allow_missing=False) -> None:
"""Add spec at path to database, locking and reading DB to sync. """Add spec at path to database, locking and reading DB to sync.
``add()`` will lock and read from the DB on disk. ``add()`` will lock and read from the DB on disk.
@ -1254,7 +1254,7 @@ def add(self, spec: "spack.spec.Spec", *, explicit: bool = False) -> None:
# TODO: ensure that spec is concrete? # TODO: ensure that spec is concrete?
# Entire add is transactional. # Entire add is transactional.
with self.write_transaction(): with self.write_transaction():
self._add(spec, explicit=explicit) self._add(spec, explicit=explicit, allow_missing=allow_missing)
def _get_matching_spec_key(self, spec: "spack.spec.Spec", **kwargs) -> str: def _get_matching_spec_key(self, spec: "spack.spec.Spec", **kwargs) -> str:
"""Get the exact spec OR get a single spec that matches.""" """Get the exact spec OR get a single spec that matches."""