Spec.from_detection now accounts for external prefix (#46063)
Change the signature of Spec.from_detection to set the external prefix, and the external modules, if they are present. Delete "spack.package_prefs.spec_externals" since it is unused.
This commit is contained in:
parent
df57e1ceb3
commit
25ba3124bd
@ -45,7 +45,9 @@ def __reduce__(self):
|
|||||||
def restore(
|
def restore(
|
||||||
spec_str: str, prefix: str, extra_attributes: Optional[Dict[str, str]]
|
spec_str: str, prefix: str, extra_attributes: Optional[Dict[str, str]]
|
||||||
) -> "DetectedPackage":
|
) -> "DetectedPackage":
|
||||||
spec = spack.spec.Spec.from_detection(spec_str=spec_str, extra_attributes=extra_attributes)
|
spec = spack.spec.Spec.from_detection(
|
||||||
|
spec_str=spec_str, external_path=prefix, extra_attributes=extra_attributes
|
||||||
|
)
|
||||||
return DetectedPackage(spec=spec, prefix=prefix)
|
return DetectedPackage(spec=spec, prefix=prefix)
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,7 +104,9 @@ def _create_executable_scripts(self, mock_executables: MockExecutables) -> List[
|
|||||||
@property
|
@property
|
||||||
def expected_specs(self) -> List[spack.spec.Spec]:
|
def expected_specs(self) -> List[spack.spec.Spec]:
|
||||||
return [
|
return [
|
||||||
spack.spec.Spec.from_detection(item.spec, extra_attributes=item.extra_attributes)
|
spack.spec.Spec.from_detection(
|
||||||
|
item.spec, external_path=self.tmpdir.name, extra_attributes=item.extra_attributes
|
||||||
|
)
|
||||||
for item in self.test.results
|
for item in self.test.results
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -246,10 +246,7 @@ def determine_spec_details(cls, prefix, objs_in_prefix):
|
|||||||
if version_str:
|
if version_str:
|
||||||
objs_by_version[version_str].append(obj)
|
objs_by_version[version_str].append(obj)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = (
|
tty.debug(f"Cannot detect the version of '{obj}' [{str(e)}]")
|
||||||
"An error occurred when trying to detect " 'the version of "{0}" [{1}]'
|
|
||||||
)
|
|
||||||
tty.debug(msg.format(obj, str(e)))
|
|
||||||
|
|
||||||
specs = []
|
specs = []
|
||||||
for version_str, objs in objs_by_version.items():
|
for version_str, objs in objs_by_version.items():
|
||||||
@ -262,27 +259,23 @@ def determine_spec_details(cls, prefix, objs_in_prefix):
|
|||||||
if isinstance(variant, str):
|
if isinstance(variant, str):
|
||||||
variant = (variant, {})
|
variant = (variant, {})
|
||||||
variant_str, extra_attributes = variant
|
variant_str, extra_attributes = variant
|
||||||
spec_str = "{0}@{1} {2}".format(cls.name, version_str, variant_str)
|
spec_str = f"{cls.name}@{version_str} {variant_str}"
|
||||||
|
|
||||||
# Pop a few reserved keys from extra attributes, since
|
# Pop a few reserved keys from extra attributes, since
|
||||||
# they have a different semantics
|
# they have a different semantics
|
||||||
external_path = extra_attributes.pop("prefix", None)
|
external_path = extra_attributes.pop("prefix", None)
|
||||||
external_modules = extra_attributes.pop("modules", None)
|
external_modules = extra_attributes.pop("modules", None)
|
||||||
try:
|
try:
|
||||||
spec = spack.spec.Spec(
|
spec = spack.spec.Spec.from_detection(
|
||||||
spec_str,
|
spec_str,
|
||||||
external_path=external_path,
|
external_path=external_path,
|
||||||
external_modules=external_modules,
|
external_modules=external_modules,
|
||||||
|
extra_attributes=extra_attributes,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = 'Parsing failed [spec_str="{0}", error={1}]'
|
tty.debug(f'Parsing failed [spec_str="{spec_str}", error={str(e)}]')
|
||||||
tty.debug(msg.format(spec_str, str(e)))
|
|
||||||
else:
|
else:
|
||||||
specs.append(
|
specs.append(spec)
|
||||||
spack.spec.Spec.from_detection(
|
|
||||||
spec, extra_attributes=extra_attributes
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return sorted(specs)
|
return sorted(specs)
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.spec
|
import spack.spec
|
||||||
from spack.config import ConfigError
|
from spack.config import ConfigError
|
||||||
from spack.util.path import canonicalize_path
|
|
||||||
from spack.version import Version
|
from spack.version import Version
|
||||||
|
|
||||||
_lesser_spec_types = {"compiler": spack.spec.CompilerSpec, "version": Version}
|
_lesser_spec_types = {"compiler": spack.spec.CompilerSpec, "version": Version}
|
||||||
@ -156,44 +155,6 @@ def preferred_variants(cls, pkg_name):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def spec_externals(spec):
|
|
||||||
"""Return a list of external specs (w/external directory path filled in),
|
|
||||||
one for each known external installation.
|
|
||||||
"""
|
|
||||||
# break circular import.
|
|
||||||
from spack.util.module_cmd import path_from_modules # noqa: F401
|
|
||||||
|
|
||||||
def _package(maybe_abstract_spec):
|
|
||||||
pkg_cls = spack.repo.PATH.get_pkg_class(spec.name)
|
|
||||||
return pkg_cls(maybe_abstract_spec)
|
|
||||||
|
|
||||||
allpkgs = spack.config.get("packages")
|
|
||||||
names = set([spec.name])
|
|
||||||
names |= set(vspec.name for vspec in _package(spec).virtuals_provided)
|
|
||||||
|
|
||||||
external_specs = []
|
|
||||||
for name in names:
|
|
||||||
pkg_config = allpkgs.get(name, {})
|
|
||||||
pkg_externals = pkg_config.get("externals", [])
|
|
||||||
for entry in pkg_externals:
|
|
||||||
spec_str = entry["spec"]
|
|
||||||
external_path = entry.get("prefix", None)
|
|
||||||
if external_path:
|
|
||||||
external_path = canonicalize_path(external_path)
|
|
||||||
external_modules = entry.get("modules", None)
|
|
||||||
external_spec = spack.spec.Spec.from_detection(
|
|
||||||
spack.spec.Spec(
|
|
||||||
spec_str, external_path=external_path, external_modules=external_modules
|
|
||||||
),
|
|
||||||
extra_attributes=entry.get("extra_attributes", {}),
|
|
||||||
)
|
|
||||||
if external_spec.intersects(spec):
|
|
||||||
external_specs.append(external_spec)
|
|
||||||
|
|
||||||
# Defensively copy returned specs
|
|
||||||
return [s.copy() for s in external_specs]
|
|
||||||
|
|
||||||
|
|
||||||
def is_spec_buildable(spec):
|
def is_spec_buildable(spec):
|
||||||
"""Return true if the spec is configured as buildable"""
|
"""Return true if the spec is configured as buildable"""
|
||||||
allpkgs = spack.config.get("packages")
|
allpkgs = spack.config.get("packages")
|
||||||
|
@ -2578,18 +2578,23 @@ def from_signed_json(stream):
|
|||||||
return Spec.from_dict(extracted_json)
|
return Spec.from_dict(extracted_json)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_detection(spec_str, extra_attributes=None):
|
def from_detection(
|
||||||
|
spec_str: str,
|
||||||
|
*,
|
||||||
|
external_path: str,
|
||||||
|
external_modules: Optional[List[str]] = None,
|
||||||
|
extra_attributes: Optional[Dict] = None,
|
||||||
|
) -> "Spec":
|
||||||
"""Construct a spec from a spec string determined during external
|
"""Construct a spec from a spec string determined during external
|
||||||
detection and attach extra attributes to it.
|
detection and attach extra attributes to it.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
spec_str (str): spec string
|
spec_str: spec string
|
||||||
extra_attributes (dict): dictionary containing extra attributes
|
external_path: prefix of the external spec
|
||||||
|
external_modules: optional module files to be loaded when the external spec is used
|
||||||
Returns:
|
extra_attributes: dictionary containing extra attributes
|
||||||
spack.spec.Spec: external spec
|
|
||||||
"""
|
"""
|
||||||
s = Spec(spec_str)
|
s = Spec(spec_str, external_path=external_path, external_modules=external_modules)
|
||||||
extra_attributes = syaml.sorted_dict(extra_attributes or {})
|
extra_attributes = syaml.sorted_dict(extra_attributes or {})
|
||||||
# This is needed to be able to validate multi-valued variants,
|
# This is needed to be able to validate multi-valued variants,
|
||||||
# otherwise they'll still be abstract in the context of detection.
|
# otherwise they'll still be abstract in the context of detection.
|
||||||
|
@ -72,8 +72,12 @@ def test_find_external_two_instances_same_package(mock_executable):
|
|||||||
|
|
||||||
def test_find_external_update_config(mutable_config):
|
def test_find_external_update_config(mutable_config):
|
||||||
entries = [
|
entries = [
|
||||||
spack.detection.DetectedPackage(Spec.from_detection("cmake@1.foo"), "/x/y1/"),
|
spack.detection.DetectedPackage(
|
||||||
spack.detection.DetectedPackage(Spec.from_detection("cmake@3.17.2"), "/x/y2/"),
|
Spec.from_detection("cmake@1.foo", external_path="/x/y1/"), "/x/y1/"
|
||||||
|
),
|
||||||
|
spack.detection.DetectedPackage(
|
||||||
|
Spec.from_detection("cmake@3.17.2", external_path="/x/y2/"), "/x/y2/"
|
||||||
|
),
|
||||||
]
|
]
|
||||||
pkg_to_entries = {"cmake": entries}
|
pkg_to_entries = {"cmake": entries}
|
||||||
|
|
||||||
@ -221,10 +225,8 @@ def fail():
|
|||||||
assert "Skipping manifest and continuing" in output
|
assert "Skipping manifest and continuing" in output
|
||||||
|
|
||||||
|
|
||||||
def test_find_external_merge(mutable_config, mutable_mock_repo):
|
def test_find_external_merge(mutable_config, mutable_mock_repo, tmp_path):
|
||||||
"""Check that 'spack find external' doesn't overwrite an existing spec
|
"""Checks that 'spack find external' doesn't overwrite an existing spec in packages.yaml."""
|
||||||
entry in packages.yaml.
|
|
||||||
"""
|
|
||||||
pkgs_cfg_init = {
|
pkgs_cfg_init = {
|
||||||
"find-externals1": {
|
"find-externals1": {
|
||||||
"externals": [{"spec": "find-externals1@1.1", "prefix": "/preexisting-prefix/"}],
|
"externals": [{"spec": "find-externals1@1.1", "prefix": "/preexisting-prefix/"}],
|
||||||
@ -234,8 +236,12 @@ def test_find_external_merge(mutable_config, mutable_mock_repo):
|
|||||||
|
|
||||||
mutable_config.update_config("packages", pkgs_cfg_init)
|
mutable_config.update_config("packages", pkgs_cfg_init)
|
||||||
entries = [
|
entries = [
|
||||||
spack.detection.DetectedPackage(Spec.from_detection("find-externals1@1.1"), "/x/y1/"),
|
spack.detection.DetectedPackage(
|
||||||
spack.detection.DetectedPackage(Spec.from_detection("find-externals1@1.2"), "/x/y2/"),
|
Spec.from_detection("find-externals1@1.1", external_path="/x/y1/"), "/x/y1/"
|
||||||
|
),
|
||||||
|
spack.detection.DetectedPackage(
|
||||||
|
Spec.from_detection("find-externals1@1.2", external_path="/x/y2/"), "/x/y2/"
|
||||||
|
),
|
||||||
]
|
]
|
||||||
pkg_to_entries = {"find-externals1": entries}
|
pkg_to_entries = {"find-externals1": entries}
|
||||||
scope = spack.config.default_modify_scope("packages")
|
scope = spack.config.default_modify_scope("packages")
|
||||||
|
@ -32,4 +32,4 @@ def determine_spec_details(cls, prefix, exes_in_prefix):
|
|||||||
match = re.search(r"find-externals1.*version\s+(\S+)", output)
|
match = re.search(r"find-externals1.*version\s+(\S+)", output)
|
||||||
if match:
|
if match:
|
||||||
version_str = match.group(1)
|
version_str = match.group(1)
|
||||||
return Spec.from_detection("find-externals1@{0}".format(version_str))
|
return Spec.from_detection(f"find-externals1@{version_str}", external_path=prefix)
|
||||||
|
@ -74,8 +74,8 @@ def setup_run_environment(self, env):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def determine_spec_details(cls, prefix, exes_in_prefix):
|
def determine_spec_details(cls, prefix, exes_in_prefix):
|
||||||
path = os.environ.get("LHAPDF_DATA_PATH", None)
|
path = os.environ.get("LHAPDF_DATA_PATH", None)
|
||||||
|
if not path:
|
||||||
|
return None
|
||||||
# unfortunately the sets are not versioned -
|
# unfortunately the sets are not versioned -
|
||||||
# just hardcode the current version and hope it is fine
|
# just hardcode the current version and hope it is fine
|
||||||
s = Spec.from_detection("lhapdfsets@6.3.0")
|
return Spec.from_detection("lhapdfsets@6.3.0", external_path=path)
|
||||||
s.external_path = path
|
|
||||||
return s if path else None
|
|
||||||
|
@ -113,7 +113,7 @@ def determine_spec_details(cls, prefix, exes_in_prefix):
|
|||||||
match = re.match(r"rustc (\S+)", output)
|
match = re.match(r"rustc (\S+)", output)
|
||||||
if match:
|
if match:
|
||||||
version_str = match.group(1)
|
version_str = match.group(1)
|
||||||
return Spec.from_detection(f"rust@{version_str}")
|
return Spec.from_detection(f"rust@{version_str}", external_path=prefix)
|
||||||
|
|
||||||
def setup_dependent_package(self, module, dependent_spec):
|
def setup_dependent_package(self, module, dependent_spec):
|
||||||
module.cargo = Executable(os.path.join(self.spec.prefix.bin, "cargo"))
|
module.cargo = Executable(os.path.join(self.spec.prefix.bin, "cargo"))
|
||||||
|
Loading…
Reference in New Issue
Block a user