Add support for nested "overrides" scopes.
This commit is contained in:
parent
b07460ab5f
commit
87cdfa2c25
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
@ -354,6 +355,15 @@ def highest_precedence_scope(self):
|
|||||||
"""Non-internal scope with highest precedence."""
|
"""Non-internal scope with highest precedence."""
|
||||||
return next(reversed(self.file_scopes), None)
|
return next(reversed(self.file_scopes), None)
|
||||||
|
|
||||||
|
def matching_scopes(self, reg_expr):
|
||||||
|
"""
|
||||||
|
List of all scopes whose names match the provided regular expression.
|
||||||
|
|
||||||
|
For example, matching_scopes(r'^command') will return all scopes
|
||||||
|
whose names begin with `command`.
|
||||||
|
"""
|
||||||
|
return [s for s in self.scopes.values() if re.search(reg_expr, s.name)]
|
||||||
|
|
||||||
def _validate_scope(self, scope):
|
def _validate_scope(self, scope):
|
||||||
"""Ensure that scope is valid in this configuration.
|
"""Ensure that scope is valid in this configuration.
|
||||||
|
|
||||||
@ -539,13 +549,25 @@ def override(path_or_scope, value=None):
|
|||||||
an internal config scope for it and push/pop that scope.
|
an internal config scope for it and push/pop that scope.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
base_name = 'overrides-'
|
||||||
if isinstance(path_or_scope, ConfigScope):
|
if isinstance(path_or_scope, ConfigScope):
|
||||||
overrides = path_or_scope
|
overrides = path_or_scope
|
||||||
config.push_scope(path_or_scope)
|
config.push_scope(path_or_scope)
|
||||||
else:
|
else:
|
||||||
overrides = InternalConfigScope('overrides')
|
# Ensure the new override gets a unique scope name
|
||||||
|
current_overrides = [s.name for s in
|
||||||
|
config.matching_scopes(r'^{0}'.format(base_name))]
|
||||||
|
num_overrides = len(current_overrides)
|
||||||
|
while True:
|
||||||
|
scope_name = '{0}{1}'.format(base_name, num_overrides)
|
||||||
|
if scope_name in current_overrides:
|
||||||
|
num_overrides += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
overrides = InternalConfigScope(scope_name)
|
||||||
config.push_scope(overrides)
|
config.push_scope(overrides)
|
||||||
config.set(path_or_scope, value, scope='overrides')
|
config.set(path_or_scope, value, scope=scope_name)
|
||||||
|
|
||||||
yield config
|
yield config
|
||||||
|
|
||||||
|
@ -627,6 +627,54 @@ def test_add_command_line_scopes(tmpdir, mutable_config):
|
|||||||
spack.config._add_command_line_scopes(mutable_config, [str(tmpdir)])
|
spack.config._add_command_line_scopes(mutable_config, [str(tmpdir)])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.nomockstage
|
||||||
|
def test_nested_override():
|
||||||
|
"""Ensure proper scope naming of nested overrides."""
|
||||||
|
# WARNING: Base name must match that used in `config.py`s `override()`.
|
||||||
|
base_name = 'overrides-'
|
||||||
|
|
||||||
|
def _check_scopes(num_expected, debug_values):
|
||||||
|
scope_names = [s.name for s in spack.config.config.scopes.values()]
|
||||||
|
|
||||||
|
for i in range(num_expected):
|
||||||
|
name = '{0}{1}'.format(base_name, i)
|
||||||
|
assert name in scope_names
|
||||||
|
|
||||||
|
data = spack.config.config.get_config('config', name)
|
||||||
|
assert data['debug'] == debug_values[i]
|
||||||
|
|
||||||
|
# Check results from single and nested override
|
||||||
|
with spack.config.override('config:debug', True):
|
||||||
|
with spack.config.override('config:debug', False):
|
||||||
|
_check_scopes(2, [True, False])
|
||||||
|
|
||||||
|
_check_scopes(1, [True])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.nomockstage
|
||||||
|
def test_alternate_override(monkeypatch):
|
||||||
|
"""Ensure proper scope naming of override when conflict present."""
|
||||||
|
# WARNING: Base name must match that used in `config.py`s `override()`.
|
||||||
|
base_name = 'overrides-'
|
||||||
|
|
||||||
|
def _matching_scopes(regexpr):
|
||||||
|
return [spack.config.InternalConfigScope('{0}1'.format(base_name))]
|
||||||
|
|
||||||
|
# Check that the alternate naming works
|
||||||
|
monkeypatch.setattr(spack.config.config, 'matching_scopes',
|
||||||
|
_matching_scopes)
|
||||||
|
|
||||||
|
with spack.config.override('config:debug', False):
|
||||||
|
name = '{0}2'.format(base_name)
|
||||||
|
|
||||||
|
scope_names = [s.name for s in spack.config.config.scopes.values() if
|
||||||
|
s.name.startswith(base_name)]
|
||||||
|
assert name in scope_names
|
||||||
|
|
||||||
|
data = spack.config.config.get_config('config', name)
|
||||||
|
assert data['debug'] is False
|
||||||
|
|
||||||
|
|
||||||
def test_immutable_scope(tmpdir):
|
def test_immutable_scope(tmpdir):
|
||||||
config_yaml = str(tmpdir.join('config.yaml'))
|
config_yaml = str(tmpdir.join('config.yaml'))
|
||||||
with open(config_yaml, 'w') as f:
|
with open(config_yaml, 'w') as f:
|
||||||
|
Loading…
Reference in New Issue
Block a user