Spec to string: show %compiler at the end (#49439)

In Spack v1.0 we plan to parse caret ^ and percent % the same. Their meaning is direct and transitive dependency respectively. It means that variants, versions, arch, platform, os, target and dag hash should go before the %, so that they apply to dependent not the %dependency.
This commit is contained in:
Harmen Stoppels 2025-03-12 18:15:34 +01:00 committed by GitHub
parent cd3068dc0b
commit a45d09abcd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 45 additions and 38 deletions

View File

@ -224,7 +224,7 @@ def rebuild_filter(s: spack.spec.Spec) -> RebuildDecision:
def _format_pruning_message(spec: spack.spec.Spec, prune: bool, reasons: List[str]) -> str:
reason_msg = ", ".join(reasons)
spec_fmt = "{name}{@version}{%compiler}{/hash:7}"
spec_fmt = "{name}{@version}{/hash:7}{%compiler}"
if not prune:
status = colorize("@*g{[x]} ")

View File

@ -330,7 +330,7 @@ def ensure_single_spec_or_die(spec, matching_specs):
if len(matching_specs) <= 1:
return
format_string = "{name}{@version}{%compiler.name}{@compiler.version}{ arch=architecture}"
format_string = "{name}{@version}{ arch=architecture} {%compiler.name}{@compiler.version}"
args = ["%s matches multiple packages." % spec, "Matching packages:"]
args += [
colorize(" @K{%s} " % s.dag_hash(7)) + s.cformat(format_string) for s in matching_specs
@ -471,12 +471,11 @@ def get_arg(name, default=None):
nfmt = "{fullname}" if namespaces else "{name}"
ffmt = ""
if full_compiler or flags:
ffmt += "{%compiler.name}"
ffmt += "{compiler_flags} {%compiler.name}"
if full_compiler:
ffmt += "{@compiler.version}"
ffmt += " {compiler_flags}"
vfmt = "{variants}" if variants else ""
format_string = nfmt + "{@version}" + ffmt + vfmt
format_string = nfmt + "{@version}" + vfmt + ffmt
def fmt(s, depth=0):
"""Formatter function for all output specs"""

View File

@ -55,7 +55,7 @@ def dependencies(parser, args):
env = ev.active_environment()
spec = spack.cmd.disambiguate_spec(specs[0], env)
format_string = "{name}{@version}{%compiler}{/hash:7}"
format_string = "{name}{@version}{/hash:7}{%compiler}"
if sys.stdout.isatty():
tty.msg("Dependencies of %s" % spec.format(format_string, color=True))
deps = spack.store.STORE.db.installed_relatives(

View File

@ -93,7 +93,7 @@ def dependents(parser, args):
env = ev.active_environment()
spec = spack.cmd.disambiguate_spec(specs[0], env)
format_string = "{name}{@version}{%compiler}{/hash:7}"
format_string = "{name}{@version}{/hash:7}{%compiler}"
if sys.stdout.isatty():
tty.msg("Dependents of %s" % spec.cformat(format_string))
deps = spack.store.STORE.db.installed_relatives(spec, "parents", args.transitive)

View File

@ -73,7 +73,7 @@
boxlib @B{dim=2} boxlib built for 2 dimensions
libdwarf @g{%intel} ^libelf@g{%gcc}
libdwarf, built with intel compiler, linked to libelf built with gcc
mvapich2 @g{%gcc} @B{fabrics=psm,mrail,sock}
mvapich2 @B{fabrics=psm,mrail,sock} @g{%gcc}
mvapich2, built with gcc compiler, with support for multiple fabrics
"""

View File

@ -383,8 +383,10 @@ def modules_cmd(parser, args, module_type, callbacks=callbacks):
query = " ".join(str(s) for s in args.constraint_specs)
msg = f"the constraint '{query}' matches multiple packages:\n"
for s in specs:
spec_fmt = "{hash:7} {name}{@version}{%compiler}"
spec_fmt += "{compiler_flags}{variants}{arch=architecture}"
spec_fmt = (
"{hash:7} {name}{@version}{compiler_flags}{variants}"
"{arch=architecture} {%compiler}"
)
msg += "\t" + s.cformat(spec_fmt) + "\n"
tty.die(msg, "In this context exactly *one* match is needed.")

View File

@ -166,7 +166,7 @@ def __init__(
" ".join(self._install_target(s.safe_name()) for s in item.prereqs),
item.target.spec_hash(),
item.target.unsafe_format(
"{name}{@version}{%compiler}{variants}{arch=architecture}"
"{name}{@version}{variants}{ arch=architecture} {%compiler}"
),
item.buildcache_flag,
)

View File

@ -643,7 +643,7 @@ def print_status(self, *specs, **kwargs):
specs.sort()
abbreviated = [
s.cformat("{name}{@version}{%compiler}{compiler_flags}{variants}")
s.cformat("{name}{@version}{compiler_flags}{variants}{%compiler}")
for s in specs
]

View File

@ -482,7 +482,7 @@ class SimpleDAG(DotGraphBuilder):
"""Simple DOT graph, with nodes colored uniformly and edges without properties"""
def node_entry(self, node):
format_option = "{name}{@version}{%compiler}{/hash:7}"
format_option = "{name}{@version}{/hash:7}{%compiler}"
return node.dag_hash(), f'[label="{node.format(format_option)}"]'
def edge_entry(self, edge):
@ -515,7 +515,7 @@ def visit(self, edge):
super().visit(edge)
def node_entry(self, node):
node_str = node.format("{name}{@version}{%compiler}{/hash:7}")
node_str = node.format("{name}{@version}{/hash:7}{%compiler}")
options = f'[label="{node_str}", group="build_dependencies", fillcolor="coral"]'
if node.dag_hash() in self.main_unified_space:
options = f'[label="{node_str}", group="main_psid"]'

View File

@ -175,15 +175,17 @@
#: Spec(Spec("string").format()) == Spec("string)"
DEFAULT_FORMAT = (
"{name}{@versions}"
"{%compiler.name}{@compiler.versions}{compiler_flags}"
"{compiler_flags}"
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
" {%compiler.name}{@compiler.versions}"
)
#: Display format, which eliminates extra `@=` in the output, for readability.
DISPLAY_FORMAT = (
"{name}{@version}"
"{%compiler.name}{@compiler.version}{compiler_flags}"
"{compiler_flags}"
"{variants}{ namespace=namespace_if_anonymous}{ arch=architecture}{/abstract_hash}"
" {%compiler.name}{@compiler.version}"
)
#: Regular expression to pull spec contents out of clearsigned signature
@ -2106,16 +2108,18 @@ def long_spec(self):
def short_spec(self):
"""Returns a version of the spec with the dependencies hashed
instead of completely enumerated."""
spec_format = "{name}{@version}{%compiler.name}{@compiler.version}"
spec_format += "{variants}{ arch=architecture}{/hash:7}"
return self.format(spec_format)
return self.format(
"{name}{@version}{variants}{ arch=architecture}"
"{/hash:7}{%compiler.name}{@compiler.version}"
)
@property
def cshort_spec(self):
"""Returns an auto-colorized version of ``self.short_spec``."""
spec_format = "{name}{@version}{%compiler.name}{@compiler.version}"
spec_format += "{variants}{ arch=architecture}{/hash:7}"
return self.cformat(spec_format)
return self.cformat(
"{name}{@version}{variants}{ arch=architecture}"
"{/hash:7}{%compiler.name}{@compiler.version}"
)
@property
def prefix(self) -> spack.util.prefix.Prefix:
@ -5295,8 +5299,10 @@ def __init__(self, spec):
class AmbiguousHashError(spack.error.SpecError):
def __init__(self, msg, *specs):
spec_fmt = "{namespace}.{name}{@version}{%compiler}{compiler_flags}"
spec_fmt += "{variants}{ arch=architecture}{/hash:7}"
spec_fmt = (
"{namespace}.{name}{@version}{compiler_flags}{variants}"
"{ arch=architecture}{/hash:7}{%compiler}"
)
specs_str = "\n " + "\n ".join(spec.format(spec_fmt) for spec in specs)
super().__init__(msg + specs_str)

View File

@ -1779,7 +1779,7 @@ def test_roots_display_with_variants():
with ev.read("test"):
out = find(output=str)
assert "boost +shared" in out
assert "boost+shared" in out
def test_uninstall_keeps_in_env(mock_stage, mock_fetch, install_mockery):

View File

@ -320,7 +320,7 @@ def test_find_very_long(database, config):
@pytest.mark.db
def test_find_show_compiler(database, config):
output = find("--no-groups", "--show-full-compiler", "mpileaks")
assert "mpileaks@2.3%gcc@10.2.1" in output
assert "mpileaks@2.3 %gcc@10.2.1" in output
@pytest.mark.db
@ -464,7 +464,7 @@ def test_environment_with_version_range_in_compiler_doesnt_fail(tmp_path):
with test_environment:
output = find()
assert "zlib%gcc@12.1.0" in output
assert "zlib %gcc@12.1.0" in output
_pkga = (

View File

@ -166,7 +166,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.COMPILER_AND_VERSION, value="%bar@1.0"),
Token(SpecTokens.VERSION, value="@2.0"),
],
"foo@2.0%bar@1.0",
"foo@2.0 %bar@1.0",
),
# Single dependency with version
dependency_with_version("openmpi ^hwloc@1.2e6"),
@ -188,7 +188,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.UNQUALIFIED_PACKAGE_NAME, value="stackwalker"),
Token(SpecTokens.VERSION, value="@8.1_1e"),
],
"mvapich_foo ^_openmpi@1.2:1.4,1.6%intel@12.1+debug~qt_4 ^stackwalker@8.1_1e",
"mvapich_foo ^_openmpi@1.2:1.4,1.6+debug~qt_4 %intel@12.1 ^stackwalker@8.1_1e",
),
(
"mvapich_foo ^_openmpi@1.2:1.4,1.6%intel@12.1~qt_4 debug=2 ^stackwalker@8.1_1e",
@ -204,7 +204,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.UNQUALIFIED_PACKAGE_NAME, value="stackwalker"),
Token(SpecTokens.VERSION, value="@8.1_1e"),
],
"mvapich_foo ^_openmpi@1.2:1.4,1.6%intel@12.1~qt_4 debug=2 ^stackwalker@8.1_1e",
"mvapich_foo ^_openmpi@1.2:1.4,1.6~qt_4 debug=2 %intel@12.1 ^stackwalker@8.1_1e",
),
(
"mvapich_foo ^_openmpi@1.2:1.4,1.6%intel@12.1 cppflags=-O3 +debug~qt_4 "
@ -222,7 +222,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.UNQUALIFIED_PACKAGE_NAME, value="stackwalker"),
Token(SpecTokens.VERSION, value="@8.1_1e"),
],
"mvapich_foo ^_openmpi@1.2:1.4,1.6%intel@12.1 cppflags=-O3 +debug~qt_4 "
"mvapich_foo ^_openmpi@1.2:1.4,1.6 cppflags=-O3 +debug~qt_4 %intel@12.1 "
"^stackwalker@8.1_1e",
),
# Specs containing YAML or JSON in the package name
@ -236,7 +236,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.UNQUALIFIED_PACKAGE_NAME, value="boost"),
Token(SpecTokens.VERSION, value="@3.1.4"),
],
"yaml-cpp@0.1.8%intel@12.1 ^boost@3.1.4",
"yaml-cpp@0.1.8 %intel@12.1 ^boost@3.1.4",
),
(
r"builtin.yaml-cpp%gcc",
@ -244,7 +244,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.FULLY_QUALIFIED_PACKAGE_NAME, value="builtin.yaml-cpp"),
Token(SpecTokens.COMPILER, value="%gcc"),
],
"yaml-cpp%gcc",
"yaml-cpp %gcc",
),
(
r"testrepo.yaml-cpp%gcc",
@ -252,7 +252,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.FULLY_QUALIFIED_PACKAGE_NAME, value="testrepo.yaml-cpp"),
Token(SpecTokens.COMPILER, value="%gcc"),
],
"yaml-cpp%gcc",
"yaml-cpp %gcc",
),
(
r"builtin.yaml-cpp@0.1.8%gcc@7.2.0 ^boost@3.1.4",
@ -264,7 +264,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.UNQUALIFIED_PACKAGE_NAME, value="boost"),
Token(SpecTokens.VERSION, value="@3.1.4"),
],
"yaml-cpp@0.1.8%gcc@7.2.0 ^boost@3.1.4",
"yaml-cpp@0.1.8 %gcc@7.2.0 ^boost@3.1.4",
),
(
r"builtin.yaml-cpp ^testrepo.boost ^zlib",
@ -491,7 +491,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.COMPILER_AND_VERSION, value="% intel @ 12.1:12.6"),
Token(SpecTokens.BOOL_VARIANT, value="+ debug"),
],
"%intel@12.1:12.6+debug",
"+debug %intel@12.1:12.6",
),
(
"@ 12.1:12.6 + debug - qt_4",
@ -516,7 +516,7 @@ def _specfile_for(spec_str, filename):
Token(SpecTokens.VERSION, value="@:0.4"),
Token(SpecTokens.COMPILER, value="% nvhpc"),
],
"@:0.4%nvhpc",
"@:0.4 %nvhpc",
),
(
"^[virtuals=mpi] openmpi",

View File

@ -54,7 +54,7 @@ def patch(self):
# it takes a very long time to rebuild!
tty.info(
"Build for "
+ self.spec["openfoam"].format("{name}{@version}{%compiler}{compiler_flags}{variants}")
+ self.spec["openfoam"].format("{name}{@version}{compiler_flags}{variants}{%compiler}")
)
def configure(self, spec, prefix):