config: create internal config scope for commands to use.
This commit is contained in:
parent
eee502cc3b
commit
c9ea957563
5 changed files with 87 additions and 13 deletions
|
@ -117,10 +117,11 @@ def init_compiler_config():
|
||||||
def compiler_config_files():
|
def compiler_config_files():
|
||||||
config_files = list()
|
config_files = list()
|
||||||
config = spack.config.get_configuration()
|
config = spack.config.get_configuration()
|
||||||
for scope in config.scopes:
|
for scope in config.file_scopes:
|
||||||
compiler_config = config.get_config('compilers', scope=scope)
|
name = scope.name
|
||||||
|
compiler_config = config.get_config('compilers', scope=name)
|
||||||
if compiler_config:
|
if compiler_config:
|
||||||
config_files.append(config.get_config_filename(scope, 'compilers'))
|
config_files.append(config.get_config_filename(name, 'compilers'))
|
||||||
return config_files
|
return config_files
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,10 @@
|
||||||
scopes_metavar = '{defaults,system,site,user}[/PLATFORM]'
|
scopes_metavar = '{defaults,system,site,user}[/PLATFORM]'
|
||||||
|
|
||||||
|
|
||||||
|
#: config scopes only used by Spack internally
|
||||||
|
internal_scopes = ['commands']
|
||||||
|
|
||||||
|
|
||||||
def _extend_with_default(validator_class):
|
def _extend_with_default(validator_class):
|
||||||
"""Add support for the 'default' attr for properties and patternProperties.
|
"""Add support for the 'default' attr for properties and patternProperties.
|
||||||
|
|
||||||
|
@ -199,6 +203,37 @@ def __repr__(self):
|
||||||
return '<ConfigScope: %s: %s>' % (self.name, self.path)
|
return '<ConfigScope: %s: %s>' % (self.name, self.path)
|
||||||
|
|
||||||
|
|
||||||
|
class InternalConfigScope(ConfigScope):
|
||||||
|
"""An internal configuration scope that is not persisted to a file.
|
||||||
|
|
||||||
|
This is for spack internal use so that command-line options and
|
||||||
|
config file settings are accessed the same way, and Spack can easily
|
||||||
|
override settings from files.
|
||||||
|
"""
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
self.sections = syaml.syaml_dict()
|
||||||
|
|
||||||
|
def get_section_filename(self, section):
|
||||||
|
raise NotImplementedError(
|
||||||
|
"Cannot get filename for InternalConfigScope.")
|
||||||
|
|
||||||
|
def get_section(self, section):
|
||||||
|
"""Just reads from an internal dictionary."""
|
||||||
|
if section not in self.sections:
|
||||||
|
self.sections[section] = None
|
||||||
|
return self.sections[section]
|
||||||
|
|
||||||
|
def write_section(self, section):
|
||||||
|
"""This only validates, as the data is already in memory."""
|
||||||
|
data = self.get_section(section)
|
||||||
|
if data is not None:
|
||||||
|
_validate_section(data, section_schemas[section])
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<InternalConfigScope: %s>' % self.name
|
||||||
|
|
||||||
|
|
||||||
class Configuration(object):
|
class Configuration(object):
|
||||||
"""A full Spack configuration, from a hierarchy of config files.
|
"""A full Spack configuration, from a hierarchy of config files.
|
||||||
|
|
||||||
|
@ -226,10 +261,15 @@ def pop_scope(self):
|
||||||
name, scope = self.scopes.popitem(last=True)
|
name, scope = self.scopes.popitem(last=True)
|
||||||
return scope
|
return scope
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file_scopes(self):
|
||||||
|
"""List of scopes with an associated file (non-internal scopes)."""
|
||||||
|
return [s for s in self.scopes.values()
|
||||||
|
if not isinstance(s, InternalConfigScope)]
|
||||||
|
|
||||||
def highest_precedence_scope(self):
|
def highest_precedence_scope(self):
|
||||||
"""Get the scope with highest precedence (prefs will override others).
|
"""Non-internal scope with highest precedence."""
|
||||||
"""
|
return next(reversed(self.file_scopes), None)
|
||||||
return list(self.scopes.values())[-1]
|
|
||||||
|
|
||||||
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.
|
||||||
|
@ -371,17 +411,19 @@ def get_configuration():
|
||||||
# configuration directory.
|
# configuration directory.
|
||||||
platform = spack.architecture.platform().name
|
platform = spack.architecture.platform().name
|
||||||
|
|
||||||
scopes = []
|
_configuration = Configuration()
|
||||||
for name, path in configuration_paths:
|
for name, path in configuration_paths:
|
||||||
# add the regular scope
|
# add the regular scope
|
||||||
scopes.append(ConfigScope(name, path))
|
_configuration.push_scope(ConfigScope(name, path))
|
||||||
|
|
||||||
# add platform-specific scope
|
# add platform-specific scope
|
||||||
plat_name = '%s/%s' % (name, platform)
|
plat_name = '%s/%s' % (name, platform)
|
||||||
plat_path = os.path.join(path, platform)
|
plat_path = os.path.join(path, platform)
|
||||||
scopes.append(ConfigScope(plat_name, plat_path))
|
_configuration.push_scope(ConfigScope(plat_name, plat_path))
|
||||||
|
|
||||||
_configuration = Configuration(*scopes)
|
# we make a special scope for spack commands so that they can
|
||||||
|
# override configuration options.
|
||||||
|
_configuration.push_scope(InternalConfigScope('commands'))
|
||||||
|
|
||||||
return _configuration
|
return _configuration
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
from llnl.util.filesystem import working_dir, mkdirp, join_path
|
from llnl.util.filesystem import working_dir, mkdirp, join_path
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
|
import spack.config
|
||||||
import spack.error
|
import spack.error
|
||||||
import spack.util.crypto as crypto
|
import spack.util.crypto as crypto
|
||||||
import spack.util.pattern as pattern
|
import spack.util.pattern as pattern
|
||||||
|
|
|
@ -38,7 +38,7 @@ def pre_run():
|
||||||
def check_compiler_yaml_version():
|
def check_compiler_yaml_version():
|
||||||
config = spack.config.get_configuration()
|
config = spack.config.get_configuration()
|
||||||
|
|
||||||
for scope in config:
|
for scope in config.file_scopes:
|
||||||
file_name = os.path.join(scope.path, 'compilers.yaml')
|
file_name = os.path.join(scope.path, 'compilers.yaml')
|
||||||
data = None
|
data = None
|
||||||
if os.path.isfile(file_name):
|
if os.path.isfile(file_name):
|
||||||
|
|
|
@ -64,9 +64,10 @@ def config(tmpdir):
|
||||||
real_configuration = spack.config._configuration
|
real_configuration = spack.config._configuration
|
||||||
scopes = [spack.config.ConfigScope(name, str(tmpdir.join(name)))
|
scopes = [spack.config.ConfigScope(name, str(tmpdir.join(name)))
|
||||||
for name in ['low', 'high']]
|
for name in ['low', 'high']]
|
||||||
spack.config._configuration = spack.config.Configuration(*scopes)
|
config = spack.config.Configuration(*scopes)
|
||||||
|
spack.config._configuration = config
|
||||||
|
|
||||||
yield
|
yield config
|
||||||
|
|
||||||
spack.config._configuration = real_configuration
|
spack.config._configuration = real_configuration
|
||||||
|
|
||||||
|
@ -420,6 +421,35 @@ def test_read_config_override_list(config, write_config_file):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_internal_config_update(config, write_config_file):
|
||||||
|
write_config_file('config', config_low, 'low')
|
||||||
|
|
||||||
|
before = config.get_config('config')
|
||||||
|
assert before['install_tree'] == 'install_tree_path'
|
||||||
|
|
||||||
|
# add an internal configuration scope
|
||||||
|
scope = spack.config.InternalConfigScope('commands')
|
||||||
|
assert 'InternalConfigScope' in repr(scope)
|
||||||
|
|
||||||
|
config.push_scope(scope)
|
||||||
|
|
||||||
|
command_config = config.get_config('config', scope='commands')
|
||||||
|
command_config['install_tree'] = 'foo/bar'
|
||||||
|
|
||||||
|
config.update_config('config', command_config, scope='commands')
|
||||||
|
|
||||||
|
after = config.get_config('config')
|
||||||
|
assert after['install_tree'] == 'foo/bar'
|
||||||
|
|
||||||
|
|
||||||
|
def test_internal_config_filename(config, write_config_file):
|
||||||
|
write_config_file('config', config_low, 'low')
|
||||||
|
config.push_scope(spack.config.InternalConfigScope('commands'))
|
||||||
|
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
config.get_config_filename('commands', 'config')
|
||||||
|
|
||||||
|
|
||||||
def test_keys_are_ordered():
|
def test_keys_are_ordered():
|
||||||
|
|
||||||
expected_order = (
|
expected_order = (
|
||||||
|
|
Loading…
Reference in a new issue