Spec.format: fix bug in dependency hash formatting (#37073)
Co-authored-by: becker33 <becker33@users.noreply.github.com>
This commit is contained in:
parent
cceeb96e06
commit
21cadf96e0
2 changed files with 56 additions and 58 deletions
|
@ -4115,6 +4115,17 @@ def write(s, c=None):
|
|||
clr.cwrite(f, stream=out, color=color)
|
||||
|
||||
def write_attribute(spec, attribute, color):
|
||||
attribute = attribute.lower()
|
||||
|
||||
sig = ""
|
||||
if attribute.startswith(("@", "%", "/")):
|
||||
# color sigils that are inside braces
|
||||
sig = attribute[0]
|
||||
attribute = attribute[1:]
|
||||
elif attribute.startswith("arch="):
|
||||
sig = " arch=" # include space as separator
|
||||
attribute = attribute[5:]
|
||||
|
||||
current = spec
|
||||
if attribute.startswith("^"):
|
||||
attribute = attribute[1:]
|
||||
|
@ -4123,16 +4134,6 @@ def write_attribute(spec, attribute, color):
|
|||
|
||||
if attribute == "":
|
||||
raise SpecFormatStringError("Format string attributes must be non-empty")
|
||||
attribute = attribute.lower()
|
||||
|
||||
sig = ""
|
||||
if attribute[0] in "@%/":
|
||||
# color sigils that are inside braces
|
||||
sig = attribute[0]
|
||||
attribute = attribute[1:]
|
||||
elif attribute.startswith("arch="):
|
||||
sig = " arch=" # include space as separator
|
||||
attribute = attribute[5:]
|
||||
|
||||
parts = attribute.split(".")
|
||||
assert parts
|
||||
|
@ -4162,9 +4163,9 @@ def write_attribute(spec, attribute, color):
|
|||
col = "#"
|
||||
if ":" in attribute:
|
||||
_, length = attribute.split(":")
|
||||
write(sig + morph(spec, spec.dag_hash(int(length))), col)
|
||||
write(sig + morph(spec, current.dag_hash(int(length))), col)
|
||||
else:
|
||||
write(sig + morph(spec, spec.dag_hash()), col)
|
||||
write(sig + morph(spec, current.dag_hash()), col)
|
||||
return
|
||||
|
||||
# Iterate over components using getattr to get next element
|
||||
|
|
|
@ -621,65 +621,62 @@ def test_spec_formatting(self, default_mock_concretization):
|
|||
# Testing named strings ie {string} and whether we get
|
||||
# the correct component
|
||||
# Mixed case intentional to test both
|
||||
# Fields are as follow
|
||||
# fmt_str: the format string to test
|
||||
# sigil: the portion that is a sigil (may be empty string)
|
||||
# prop: the property to get
|
||||
# component: subcomponent of spec from which to get property
|
||||
package_segments = [
|
||||
("{NAME}", "name"),
|
||||
("{VERSION}", "versions"),
|
||||
("{compiler}", "compiler"),
|
||||
("{compiler_flags}", "compiler_flags"),
|
||||
("{variants}", "variants"),
|
||||
("{architecture}", "architecture"),
|
||||
("{NAME}", "", "name", lambda spec: spec),
|
||||
("{VERSION}", "", "versions", lambda spec: spec),
|
||||
("{compiler}", "", "compiler", lambda spec: spec),
|
||||
("{compiler_flags}", "", "compiler_flags", lambda spec: spec),
|
||||
("{variants}", "", "variants", lambda spec: spec),
|
||||
("{architecture}", "", "architecture", lambda spec: spec),
|
||||
("{@VERSIONS}", "@", "version", lambda spec: spec),
|
||||
("{%compiler}", "%", "compiler", lambda spec: spec),
|
||||
("{arch=architecture}", "arch=", "architecture", lambda spec: spec),
|
||||
("{compiler.name}", "", "name", lambda spec: spec.compiler),
|
||||
("{compiler.version}", "", "versions", lambda spec: spec.compiler),
|
||||
("{%compiler.name}", "%", "name", lambda spec: spec.compiler),
|
||||
("{@compiler.version}", "@", "version", lambda spec: spec.compiler),
|
||||
("{architecture.platform}", "", "platform", lambda spec: spec.architecture),
|
||||
("{architecture.os}", "", "os", lambda spec: spec.architecture),
|
||||
("{architecture.target}", "", "target", lambda spec: spec.architecture),
|
||||
("{prefix}", "", "prefix", lambda spec: spec),
|
||||
]
|
||||
|
||||
sigil_package_segments = [
|
||||
("{@VERSIONS}", "@" + str(spec.version)),
|
||||
("{%compiler}", "%" + str(spec.compiler)),
|
||||
("{arch=architecture}", "arch=" + str(spec.architecture)),
|
||||
]
|
||||
|
||||
compiler_segments = [("{compiler.name}", "name"), ("{compiler.version}", "versions")]
|
||||
|
||||
sigil_compiler_segments = [
|
||||
("{%compiler.name}", "%" + spec.compiler.name),
|
||||
("{@compiler.version}", "@" + str(spec.compiler.version)),
|
||||
]
|
||||
|
||||
architecture_segments = [
|
||||
("{architecture.platform}", "platform"),
|
||||
("{architecture.os}", "os"),
|
||||
("{architecture.target}", "target"),
|
||||
hash_segments = [
|
||||
("{hash:7}", "", lambda s: s.dag_hash(7)),
|
||||
("{/hash}", "/", lambda s: "/" + s.dag_hash()),
|
||||
]
|
||||
|
||||
other_segments = [
|
||||
("{spack_root}", spack.paths.spack_root),
|
||||
("{spack_install}", spack.store.layout.root),
|
||||
("{hash:7}", spec.dag_hash(7)),
|
||||
("{/hash}", "/" + spec.dag_hash()),
|
||||
]
|
||||
|
||||
for named_str, prop in package_segments:
|
||||
expected = getattr(spec, prop, "")
|
||||
actual = spec.format(named_str)
|
||||
assert str(expected).strip() == actual
|
||||
def depify(depname, fmt_str, sigil):
|
||||
sig = len(sigil)
|
||||
opening = fmt_str[: 1 + sig]
|
||||
closing = fmt_str[1 + sig :]
|
||||
return spec[depname], opening + f"^{depname}." + closing
|
||||
|
||||
for named_str, expected in sigil_package_segments:
|
||||
actual = spec.format(named_str)
|
||||
assert expected == actual
|
||||
def check_prop(check_spec, fmt_str, prop, getter):
|
||||
actual = spec.format(fmt_str)
|
||||
expected = getter(check_spec)
|
||||
assert actual == str(expected).strip()
|
||||
|
||||
compiler = spec.compiler
|
||||
for named_str, prop in compiler_segments:
|
||||
expected = getattr(compiler, prop, "")
|
||||
actual = spec.format(named_str)
|
||||
assert str(expected) == actual
|
||||
for named_str, sigil, prop, get_component in package_segments:
|
||||
getter = lambda s: sigil + str(getattr(get_component(s), prop, ""))
|
||||
check_prop(spec, named_str, prop, getter)
|
||||
mpi, fmt_str = depify("mpi", named_str, sigil)
|
||||
check_prop(mpi, fmt_str, prop, getter)
|
||||
|
||||
for named_str, expected in sigil_compiler_segments:
|
||||
actual = spec.format(named_str)
|
||||
assert expected == actual
|
||||
|
||||
arch = spec.architecture
|
||||
for named_str, prop in architecture_segments:
|
||||
expected = getattr(arch, prop, "")
|
||||
actual = spec.format(named_str)
|
||||
assert str(expected) == actual
|
||||
for named_str, sigil, getter in hash_segments:
|
||||
assert spec.format(named_str) == getter(spec)
|
||||
callpath, fmt_str = depify("callpath", named_str, sigil)
|
||||
assert spec.format(fmt_str) == getter(callpath)
|
||||
|
||||
for named_str, expected in other_segments:
|
||||
actual = spec.format(named_str)
|
||||
|
|
Loading…
Reference in a new issue