"spack config add": support values with ":" (#39831)
This is a fixed version of b72a268
* That commit would discard the final key component (so if you set
"config:install_tree:root", it would discard "root" and just set
install tree).
* When setting key:"value", with the quotes, that commit would
discard the quotes, which would confuse the system if adding a
value like "{example}" (the "{" character indicates a dictionary).
This commit retains the quotes.
This commit is contained in:
parent
642451e047
commit
40c4c81c19
@ -857,12 +857,12 @@ def add_from_file(filename, scope=None):
|
|||||||
def add(fullpath, scope=None):
|
def add(fullpath, scope=None):
|
||||||
"""Add the given configuration to the specified config scope.
|
"""Add the given configuration to the specified config scope.
|
||||||
Add accepts a path. If you want to add from a filename, use add_from_file"""
|
Add accepts a path. If you want to add from a filename, use add_from_file"""
|
||||||
|
|
||||||
components = process_config_path(fullpath)
|
components = process_config_path(fullpath)
|
||||||
|
|
||||||
has_existing_value = True
|
has_existing_value = True
|
||||||
path = ""
|
path = ""
|
||||||
override = False
|
override = False
|
||||||
|
value = syaml.load_config(components[-1])
|
||||||
for idx, name in enumerate(components[:-1]):
|
for idx, name in enumerate(components[:-1]):
|
||||||
# First handle double colons in constructing path
|
# First handle double colons in constructing path
|
||||||
colon = "::" if override else ":" if path else ""
|
colon = "::" if override else ":" if path else ""
|
||||||
@ -883,14 +883,14 @@ def add(fullpath, scope=None):
|
|||||||
existing = get_valid_type(path)
|
existing = get_valid_type(path)
|
||||||
|
|
||||||
# construct value from this point down
|
# construct value from this point down
|
||||||
value = syaml.load_config(components[-1])
|
|
||||||
for component in reversed(components[idx + 1 : -1]):
|
for component in reversed(components[idx + 1 : -1]):
|
||||||
value = {component: value}
|
value = {component: value}
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if override:
|
||||||
|
path += "::"
|
||||||
|
|
||||||
if has_existing_value:
|
if has_existing_value:
|
||||||
path, _, value = fullpath.rpartition(":")
|
|
||||||
value = syaml.load_config(value)
|
|
||||||
existing = get(path, scope=scope)
|
existing = get(path, scope=scope)
|
||||||
|
|
||||||
# append values to lists
|
# append values to lists
|
||||||
@ -1231,11 +1231,17 @@ def they_are(t):
|
|||||||
return copy.copy(source)
|
return copy.copy(source)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process a path argument to config.set() that may contain overrides ('::' or
|
|
||||||
# trailing ':')
|
|
||||||
#
|
|
||||||
def process_config_path(path):
|
def process_config_path(path):
|
||||||
|
"""Process a path argument to config.set() that may contain overrides ('::' or
|
||||||
|
trailing ':')
|
||||||
|
|
||||||
|
Note: quoted value path components will be processed as a single value (escaping colons)
|
||||||
|
quoted path components outside of the value will be considered ill formed and will
|
||||||
|
raise.
|
||||||
|
e.g. `this:is:a:path:'value:with:colon'` will yield:
|
||||||
|
|
||||||
|
[this, is, a, path, value:with:colon]
|
||||||
|
"""
|
||||||
result = []
|
result = []
|
||||||
if path.startswith(":"):
|
if path.startswith(":"):
|
||||||
raise syaml.SpackYAMLError("Illegal leading `:' in path `{0}'".format(path), "")
|
raise syaml.SpackYAMLError("Illegal leading `:' in path `{0}'".format(path), "")
|
||||||
@ -1263,6 +1269,17 @@ def process_config_path(path):
|
|||||||
front.append = True
|
front.append = True
|
||||||
|
|
||||||
result.append(front)
|
result.append(front)
|
||||||
|
|
||||||
|
quote = "['\"]"
|
||||||
|
not_quote = "[^'\"]"
|
||||||
|
|
||||||
|
if re.match(f"^{quote}", path):
|
||||||
|
m = re.match(rf"^({quote}{not_quote}+{quote})$", path)
|
||||||
|
if not m:
|
||||||
|
raise ValueError("Quotes indicate value, but there are additional path entries")
|
||||||
|
result.append(m.group(1))
|
||||||
|
break
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -277,6 +277,25 @@ def test_add_config_path(mutable_config):
|
|||||||
compilers = spack.config.get("packages")["all"]["compiler"]
|
compilers = spack.config.get("packages")["all"]["compiler"]
|
||||||
assert "gcc" in compilers
|
assert "gcc" in compilers
|
||||||
|
|
||||||
|
# Try quotes to escape brackets
|
||||||
|
path = "config:install_tree:projections:cmake:\
|
||||||
|
'{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}'"
|
||||||
|
spack.config.add(path)
|
||||||
|
set_value = spack.config.get("config")["install_tree"]["projections"]["cmake"]
|
||||||
|
assert set_value == "{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}"
|
||||||
|
|
||||||
|
# NOTE:
|
||||||
|
# The config path: "config:install_tree:root:<path>" is unique in that it can accept multiple
|
||||||
|
# schemas (such as a dropped "root" component) which is atypical and may lead to passing tests
|
||||||
|
# when the behavior is in reality incorrect.
|
||||||
|
# the config path below is such that no subkey accepts a string as a valid entry in our schema
|
||||||
|
|
||||||
|
# try quotes to escape colons
|
||||||
|
path = "config:build_stage:'C:\\path\\to\\config.yaml'"
|
||||||
|
spack.config.add(path)
|
||||||
|
set_value = spack.config.get("config")["build_stage"]
|
||||||
|
assert "C:\\path\\to\\config.yaml" in set_value
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.regression("17543,23259")
|
@pytest.mark.regression("17543,23259")
|
||||||
def test_add_config_path_with_enumerated_type(mutable_config):
|
def test_add_config_path_with_enumerated_type(mutable_config):
|
||||||
|
Loading…
Reference in New Issue
Block a user