Remove the old spec format in configuration (#37425)

The format was deprecated in v0.15
This commit is contained in:
Massimiliano Culpo 2023-05-04 16:59:11 +02:00 committed by GitHub
parent e6d37b3b61
commit 95e61f2fdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 1 additions and 303 deletions

View File

@ -4080,15 +4080,7 @@ def format(self, format_string=default_format, **kwargs):
Spec format strings use ``\`` as the escape character. Use
``\{`` and ``\}`` for literal braces, and ``\\`` for the
literal ``\`` character. Also use ``\$`` for the literal ``$``
to differentiate from previous, deprecated format string
syntax.
The previous format strings are deprecated. They can still be
accessed by the ``old_format`` method. The ``format`` method
will call ``old_format`` if the character ``$`` appears
unescaped in the format string.
literal ``\`` character.
Args:
format_string (str): string containing the format to be expanded
@ -4099,10 +4091,6 @@ def format(self, format_string=default_format, **kwargs):
that accepts a string and returns another one
"""
# If we have an unescaped $ sigil, use the deprecated format strings
if re.search(r"[^\\]*\$", format_string):
return self.old_format(format_string, **kwargs)
color = kwargs.get("color", False)
transform = kwargs.get("transform", {})
@ -4252,250 +4240,6 @@ def write_attribute(spec, attribute, color):
formatted_spec = out.getvalue()
return formatted_spec.strip()
def old_format(self, format_string="$_$@$%@+$+$=", **kwargs):
"""
The format strings you can provide are::
$_ Package name
$. Full package name (with namespace)
$@ Version with '@' prefix
$% Compiler with '%' prefix
$%@ Compiler with '%' prefix & compiler version with '@' prefix
$%+ Compiler with '%' prefix & compiler flags prefixed by name
$%@+ Compiler, compiler version, and compiler flags with same
prefixes as above
$+ Options
$= Architecture prefixed by 'arch='
$/ 7-char prefix of DAG hash with '-' prefix
$$ $
You can also use full-string versions, which elide the prefixes::
${PACKAGE} Package name
${FULLPACKAGE} Full package name (with namespace)
${VERSION} Version
${COMPILER} Full compiler string
${COMPILERNAME} Compiler name
${COMPILERVER} Compiler version
${COMPILERFLAGS} Compiler flags
${OPTIONS} Options
${ARCHITECTURE} Architecture
${PLATFORM} Platform
${OS} Operating System
${TARGET} Target
${SHA1} Dependencies 8-char sha1 prefix
${HASH:len} DAG hash with optional length specifier
${DEP:name:OPTION} Evaluates as OPTION would for self['name']
${SPACK_ROOT} The spack root directory
${SPACK_INSTALL} The default spack install directory,
${SPACK_PREFIX}/opt
${PREFIX} The package prefix
${NAMESPACE} The package namespace
Note these are case-insensitive: for example you can specify either
``${PACKAGE}`` or ``${package}``.
Optionally you can provide a width, e.g. ``$20_`` for a 20-wide name.
Like printf, you can provide '-' for left justification, e.g.
``$-20_`` for a left-justified name.
Anything else is copied verbatim into the output stream.
Args:
format_string (str): string containing the format to be expanded
Keyword Args:
color (bool): True if returned string is colored
transform (dict): maps full-string formats to a callable \
that accepts a string and returns another one
Examples:
The following line:
.. code-block:: python
s = spec.format('$_$@$+')
translates to the name, version, and options of the package, but no
dependencies, arch, or compiler.
TODO: allow, e.g., ``$6#`` to customize short hash length
TODO: allow, e.g., ``$//`` for full hash.
"""
warnings.warn(
"Using the old Spec.format method."
" This method was deprecated in Spack v0.15 and will be removed in Spack v0.20"
)
color = kwargs.get("color", False)
# Dictionary of transformations for named tokens
token_transforms = dict((k.upper(), v) for k, v in kwargs.get("transform", {}).items())
length = len(format_string)
out = io.StringIO()
named = escape = compiler = False
named_str = fmt = ""
def write(s, c=None):
f = clr.cescape(s)
if c is not None:
f = color_formats[c] + f + "@."
clr.cwrite(f, stream=out, color=color)
iterator = enumerate(format_string)
for i, c in iterator:
if escape:
fmt = "%"
if c == "-":
fmt += c
i, c = next(iterator)
while c in "0123456789":
fmt += c
i, c = next(iterator)
fmt += "s"
if c == "_":
name = self.name if self.name else ""
out.write(fmt % name)
elif c == ".":
name = self.fullname if self.fullname else ""
out.write(fmt % name)
elif c == "@":
if self.versions and self.versions != _any_version:
write(fmt % (c + str(self.versions)), c)
elif c == "%":
if self.compiler:
write(fmt % (c + str(self.compiler.name)), c)
compiler = True
elif c == "+":
if self.variants:
write(fmt % str(self.variants), c)
elif c == "=":
if self.architecture and str(self.architecture):
a_str = " arch" + c + str(self.architecture) + " "
write(fmt % (a_str), c)
elif c == "/":
out.write("/" + fmt % (self.dag_hash(7)))
elif c == "$":
if fmt != "%s":
raise ValueError("Can't use format width with $$.")
out.write("$")
elif c == "{":
named = True
named_str = ""
escape = False
elif compiler:
if c == "@":
if (
self.compiler
and self.compiler.versions
and self.compiler.versions != _any_version
):
write(c + str(self.compiler.versions), "%")
elif c == "+":
if self.compiler_flags:
write(fmt % str(self.compiler_flags), "%")
compiler = False
elif c == "$":
escape = True
compiler = False
else:
out.write(c)
compiler = False
elif named:
if not c == "}":
if i == length - 1:
raise ValueError(
"Error: unterminated ${ in format:" "'%s'" % format_string
)
named_str += c
continue
named_str = named_str.upper()
# Retrieve the token transformation from the dictionary.
#
# The default behavior is to leave the string unchanged
# (`lambda x: x` is the identity function)
transform = token_transforms.get(named_str, lambda s, x: x)
if named_str == "PACKAGE":
name = self.name if self.name else ""
write(fmt % transform(self, name))
elif named_str == "FULLPACKAGE":
name = self.fullname if self.fullname else ""
write(fmt % transform(self, name))
elif named_str == "VERSION":
if self.versions and self.versions != _any_version:
write(fmt % transform(self, str(self.versions)), "@")
elif named_str == "COMPILER":
if self.compiler:
write(fmt % transform(self, self.compiler), "%")
elif named_str == "COMPILERNAME":
if self.compiler:
write(fmt % transform(self, self.compiler.name), "%")
elif named_str in ["COMPILERVER", "COMPILERVERSION"]:
if self.compiler:
write(fmt % transform(self, self.compiler.versions), "%")
elif named_str == "COMPILERFLAGS":
if self.compiler:
write(fmt % transform(self, str(self.compiler_flags)), "%")
elif named_str == "OPTIONS":
if self.variants:
write(fmt % transform(self, str(self.variants)), "+")
elif named_str in ["ARCHITECTURE", "PLATFORM", "TARGET", "OS"]:
if self.architecture and str(self.architecture):
if named_str == "ARCHITECTURE":
write(fmt % transform(self, str(self.architecture)), "=")
elif named_str == "PLATFORM":
platform = str(self.architecture.platform)
write(fmt % transform(self, platform), "=")
elif named_str == "OS":
operating_sys = str(self.architecture.os)
write(fmt % transform(self, operating_sys), "=")
elif named_str == "TARGET":
target = str(self.architecture.target)
write(fmt % transform(self, target), "=")
elif named_str == "SHA1":
if self.dependencies:
out.write(fmt % transform(self, str(self.dag_hash(7))))
elif named_str == "SPACK_ROOT":
out.write(fmt % transform(self, spack.paths.prefix))
elif named_str == "SPACK_INSTALL":
out.write(fmt % transform(self, spack.store.root))
elif named_str == "PREFIX":
out.write(fmt % transform(self, self.prefix))
elif named_str.startswith("HASH"):
if named_str.startswith("HASH:"):
_, hashlen = named_str.split(":")
hashlen = int(hashlen)
else:
hashlen = None
out.write(fmt % (self.dag_hash(hashlen)))
elif named_str == "NAMESPACE":
out.write(fmt % transform(self, self.namespace))
elif named_str.startswith("DEP:"):
_, dep_name, dep_option = named_str.lower().split(":", 2)
dep_spec = self[dep_name]
out.write(fmt % (dep_spec.format("${%s}" % dep_option)))
named = False
elif c == "$":
escape = True
if i == length - 1:
raise ValueError("Error: unterminated $ in format: '%s'" % format_string)
else:
out.write(c)
result = out.getvalue()
return result
def cformat(self, *args, **kwargs):
"""Same as format, but color defaults to auto instead of False."""
kwargs = kwargs.copy()

View File

@ -713,52 +713,6 @@ def test_spec_formatting_escapes(self, default_mock_concretization):
with pytest.raises(SpecFormatStringError):
spec.format(fmt_str)
def test_spec_deprecated_formatting(self):
spec = Spec("libelf cflags==-O2")
spec.concretize()
# Since the default is the full spec see if the string rep of
# spec is the same as the output of spec.format()
# ignoring whitespace (though should we?)
assert str(spec) == spec.format("$_$@$%@+$+$=").strip()
# Testing named strings ie {string} and whether we get
# the correct component
# Mixed case intentional for testing both
package_segments = [
("${PACKAGE}", "name"),
("${VERSION}", "versions"),
("${compiler}", "compiler"),
("${compilerflags}", "compiler_flags"),
("${options}", "variants"),
("${architecture}", "architecture"),
]
compiler_segments = [("${compilername}", "name"), ("${compilerver}", "versions")]
architecture_segments = [
("${PLATFORM}", "platform"),
("${OS}", "os"),
("${TARGET}", "target"),
]
for named_str, prop in package_segments:
expected = getattr(spec, prop, "")
actual = spec.format(named_str)
assert str(expected) == actual
compiler = spec.compiler
for named_str, prop in compiler_segments:
expected = getattr(compiler, prop, "")
actual = spec.format(named_str)
assert str(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
@pytest.mark.regression("9908")
def test_spec_flags_maintain_order(self):
# Spack was assembling flags in a manner that could result in