summaryrefslogtreecommitdiff
path: root/lib/spack/spack/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/config.py')
-rw-r--r--lib/spack/spack/config.py50
1 files changed, 40 insertions, 10 deletions
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index c47eb68e09..989b3da169 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -266,7 +266,7 @@ def _read_config_file(filename, schema):
try:
tty.debug("Reading config file %s" % filename)
with open(filename) as f:
- data = syaml.load(f)
+ data = _mark_overrides(syaml.load(f))
if data:
validate_section(data, schema)
@@ -288,6 +288,34 @@ def clear_config_caches():
scope.clear()
+def override(string):
+ """Test if a spack YAML string is an override.
+
+ See ``spack_yaml`` for details. Keys in Spack YAML can end in `::`,
+ and if they do, their values completely replace lower-precedence
+ configs instead of merging into them.
+
+ """
+ return hasattr(string, 'override') and string.override
+
+
+def _mark_overrides(data):
+ if isinstance(data, list):
+ return [_mark_overrides(elt) for elt in data]
+
+ elif isinstance(data, dict):
+ marked = {}
+ for key, val in data.iteritems():
+ if isinstance(key, basestring) and key.endswith(':'):
+ key = syaml.syaml_str(key[:-1])
+ key.override = True
+ marked[key] = _mark_overrides(val)
+ return marked
+
+ else:
+ return data
+
+
def _merge_yaml(dest, source):
"""Merges source into dest; entries in source take precedence over dest.
@@ -320,9 +348,11 @@ def _merge_yaml(dest, source):
# Source dict is merged into dest.
elif they_are(dict):
for sk, sv in source.iteritems():
- if sk not in dest:
+ if override(sk) or sk not in dest:
+ # if sk ended with ::, or if it's new, completely override
dest[sk] = copy.copy(sv)
else:
+ # otherwise, merge the YAML
dest[sk] = _merge_yaml(dest[sk], source[sk])
return dest
@@ -371,18 +401,18 @@ def get_config(section, scope=None):
if not data or not isinstance(data, dict):
continue
- # Allow complete override of site config with '<section>::'
- override_key = section + ':'
- if not (section in data or override_key in data):
+ if section not in data:
tty.warn("Skipping bad configuration file: '%s'" % scope.path)
continue
- if override_key in data:
- merged_section = data[override_key]
- else:
- merged_section = _merge_yaml(merged_section, data[section])
+ merged_section = _merge_yaml(merged_section, data)
+
+ # no config files -- empty config.
+ if section not in merged_section:
+ return {}
- return merged_section
+ # take the top key off before returning.
+ return merged_section[section]
def get_config_filename(scope, section):