config: fix class hierarchy (#45044)
1. Avoid that `self.path` is of type `Optional[str]` 2. Simplify immutable config with a property.
This commit is contained in:
parent
95cf341b50
commit
1d8bdcfc04
@ -129,10 +129,10 @@ def _bootstrap_config_scopes() -> Sequence["spack.config.ConfigScope"]:
|
|||||||
configuration_paths = (spack.config.CONFIGURATION_DEFAULTS_PATH, ("bootstrap", _config_path()))
|
configuration_paths = (spack.config.CONFIGURATION_DEFAULTS_PATH, ("bootstrap", _config_path()))
|
||||||
for name, path in configuration_paths:
|
for name, path in configuration_paths:
|
||||||
platform = spack.platforms.host().name
|
platform = spack.platforms.host().name
|
||||||
platform_scope = spack.config.ConfigScope(
|
platform_scope = spack.config.DirectoryConfigScope(
|
||||||
"/".join([name, platform]), os.path.join(path, platform)
|
f"{name}/{platform}", os.path.join(path, platform)
|
||||||
)
|
)
|
||||||
generic_scope = spack.config.ConfigScope(name, path)
|
generic_scope = spack.config.DirectoryConfigScope(name, path)
|
||||||
config_scopes.extend([generic_scope, platform_scope])
|
config_scopes.extend([generic_scope, platform_scope])
|
||||||
msg = "[BOOTSTRAP CONFIG SCOPE] name={0}, path={1}"
|
msg = "[BOOTSTRAP CONFIG SCOPE] name={0}, path={1}"
|
||||||
tty.debug(msg.format(generic_scope.name, generic_scope.path))
|
tty.debug(msg.format(generic_scope.name, generic_scope.path))
|
||||||
|
@ -809,7 +809,8 @@ def ensure_expected_target_path(path):
|
|||||||
cli_scopes = [
|
cli_scopes = [
|
||||||
os.path.relpath(s.path, concrete_env_dir)
|
os.path.relpath(s.path, concrete_env_dir)
|
||||||
for s in cfg.scopes().values()
|
for s in cfg.scopes().values()
|
||||||
if isinstance(s, cfg.ImmutableConfigScope)
|
if not s.writable
|
||||||
|
and isinstance(s, (cfg.DirectoryConfigScope))
|
||||||
and s.path not in env_includes
|
and s.path not in env_includes
|
||||||
and os.path.exists(s.path)
|
and os.path.exists(s.path)
|
||||||
]
|
]
|
||||||
|
@ -165,7 +165,7 @@ def _reset(args):
|
|||||||
if not ok_to_continue:
|
if not ok_to_continue:
|
||||||
raise RuntimeError("Aborting")
|
raise RuntimeError("Aborting")
|
||||||
|
|
||||||
for scope in spack.config.CONFIG.file_scopes:
|
for scope in spack.config.CONFIG.writable_scopes:
|
||||||
# The default scope should stay untouched
|
# The default scope should stay untouched
|
||||||
if scope.name == "defaults":
|
if scope.name == "defaults":
|
||||||
continue
|
continue
|
||||||
|
@ -264,7 +264,9 @@ def config_remove(args):
|
|||||||
def _can_update_config_file(scope: spack.config.ConfigScope, cfg_file):
|
def _can_update_config_file(scope: spack.config.ConfigScope, cfg_file):
|
||||||
if isinstance(scope, spack.config.SingleFileScope):
|
if isinstance(scope, spack.config.SingleFileScope):
|
||||||
return fs.can_access(cfg_file)
|
return fs.can_access(cfg_file)
|
||||||
return fs.can_write_to_dir(scope.path) and fs.can_access(cfg_file)
|
elif isinstance(scope, spack.config.DirectoryConfigScope):
|
||||||
|
return fs.can_write_to_dir(scope.path) and fs.can_access(cfg_file)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _config_change_requires_scope(path, spec, scope, match_spec=None):
|
def _config_change_requires_scope(path, spec, scope, match_spec=None):
|
||||||
@ -362,14 +364,11 @@ def config_change(args):
|
|||||||
def config_update(args):
|
def config_update(args):
|
||||||
# Read the configuration files
|
# Read the configuration files
|
||||||
spack.config.CONFIG.get_config(args.section, scope=args.scope)
|
spack.config.CONFIG.get_config(args.section, scope=args.scope)
|
||||||
updates: List[spack.config.ConfigScope] = list(
|
updates: List[spack.config.ConfigScope] = [
|
||||||
filter(
|
x
|
||||||
lambda s: not isinstance(
|
for x in spack.config.CONFIG.format_updates[args.section]
|
||||||
s, (spack.config.InternalConfigScope, spack.config.ImmutableConfigScope)
|
if not isinstance(x, spack.config.InternalConfigScope) and x.writable
|
||||||
),
|
]
|
||||||
spack.config.CONFIG.format_updates[args.section],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
cannot_overwrite, skip_system_scope = [], False
|
cannot_overwrite, skip_system_scope = [], False
|
||||||
for scope in updates:
|
for scope in updates:
|
||||||
@ -447,7 +446,7 @@ def _can_revert_update(scope_dir, cfg_file, bkp_file):
|
|||||||
|
|
||||||
|
|
||||||
def config_revert(args):
|
def config_revert(args):
|
||||||
scopes = [args.scope] if args.scope else [x.name for x in spack.config.CONFIG.file_scopes]
|
scopes = [args.scope] if args.scope else [x.name for x in spack.config.CONFIG.writable_scopes]
|
||||||
|
|
||||||
# Search for backup files in the configuration scopes
|
# Search for backup files in the configuration scopes
|
||||||
Entry = collections.namedtuple("Entry", ["scope", "cfg", "bkp"])
|
Entry = collections.namedtuple("Entry", ["scope", "cfg", "bkp"])
|
||||||
|
@ -260,7 +260,7 @@ def _init_compiler_config(
|
|||||||
def compiler_config_files():
|
def compiler_config_files():
|
||||||
config_files = list()
|
config_files = list()
|
||||||
config = spack.config.CONFIG
|
config = spack.config.CONFIG
|
||||||
for scope in config.file_scopes:
|
for scope in config.writable_scopes:
|
||||||
name = scope.name
|
name = scope.name
|
||||||
compiler_config = config.get("compilers", scope=name)
|
compiler_config = config.get("compilers", scope=name)
|
||||||
if compiler_config:
|
if compiler_config:
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Type, Union
|
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from llnl.util import filesystem, lang, tty
|
from llnl.util import filesystem, lang, tty
|
||||||
|
|
||||||
@ -117,21 +117,39 @@
|
|||||||
|
|
||||||
|
|
||||||
class ConfigScope:
|
class ConfigScope:
|
||||||
"""This class represents a configuration scope.
|
def __init__(self, name: str) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.writable = False
|
||||||
|
self.sections = syaml.syaml_dict()
|
||||||
|
|
||||||
A scope is one directory containing named configuration files.
|
def get_section_filename(self, section: str) -> str:
|
||||||
Each file is a config "section" (e.g., mirrors, compilers, etc.).
|
raise NotImplementedError
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, name, path) -> None:
|
def get_section(self, section: str) -> Optional[YamlConfigDict]:
|
||||||
self.name = name # scope name.
|
raise NotImplementedError
|
||||||
self.path = path # path to directory containing configs.
|
|
||||||
self.sections = syaml.syaml_dict() # sections read from config files.
|
def _write_section(self, section: str) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_platform_dependent(self) -> bool:
|
def is_platform_dependent(self) -> bool:
|
||||||
"""Returns true if the scope name is platform specific"""
|
return False
|
||||||
return os.sep in self.name
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
"""Empty cached config information."""
|
||||||
|
self.sections = syaml.syaml_dict()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<ConfigScope: {self.name}>"
|
||||||
|
|
||||||
|
|
||||||
|
class DirectoryConfigScope(ConfigScope):
|
||||||
|
"""Config scope backed by a directory containing one file per section."""
|
||||||
|
|
||||||
|
def __init__(self, name: str, path: str, *, writable: bool = True) -> None:
|
||||||
|
super().__init__(name)
|
||||||
|
self.path = path
|
||||||
|
self.writable = writable
|
||||||
|
|
||||||
def get_section_filename(self, section: str) -> str:
|
def get_section_filename(self, section: str) -> str:
|
||||||
"""Returns the filename associated with a given section"""
|
"""Returns the filename associated with a given section"""
|
||||||
@ -148,6 +166,9 @@ def get_section(self, section: str) -> Optional[YamlConfigDict]:
|
|||||||
return self.sections[section]
|
return self.sections[section]
|
||||||
|
|
||||||
def _write_section(self, section: str) -> None:
|
def _write_section(self, section: str) -> None:
|
||||||
|
if not self.writable:
|
||||||
|
raise ConfigError(f"Cannot write to immutable scope {self}")
|
||||||
|
|
||||||
filename = self.get_section_filename(section)
|
filename = self.get_section_filename(section)
|
||||||
data = self.get_section(section)
|
data = self.get_section(section)
|
||||||
if data is None:
|
if data is None:
|
||||||
@ -164,19 +185,23 @@ def _write_section(self, section: str) -> None:
|
|||||||
except (syaml.SpackYAMLError, OSError) as e:
|
except (syaml.SpackYAMLError, OSError) as e:
|
||||||
raise ConfigFileError(f"cannot write to '{filename}'") from e
|
raise ConfigFileError(f"cannot write to '{filename}'") from e
|
||||||
|
|
||||||
def clear(self) -> None:
|
@property
|
||||||
"""Empty cached config information."""
|
def is_platform_dependent(self) -> bool:
|
||||||
self.sections = syaml.syaml_dict()
|
"""Returns true if the scope name is platform specific"""
|
||||||
|
return "/" in self.name
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<ConfigScope: {self.name}: {self.path}>"
|
|
||||||
|
|
||||||
|
|
||||||
class SingleFileScope(ConfigScope):
|
class SingleFileScope(ConfigScope):
|
||||||
"""This class represents a configuration scope in a single YAML file."""
|
"""This class represents a configuration scope in a single YAML file."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, name: str, path: str, schema: YamlConfigDict, yaml_path: Optional[List[str]] = None
|
self,
|
||||||
|
name: str,
|
||||||
|
path: str,
|
||||||
|
schema: YamlConfigDict,
|
||||||
|
*,
|
||||||
|
yaml_path: Optional[List[str]] = None,
|
||||||
|
writable: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Similar to ``ConfigScope`` but can be embedded in another schema.
|
"""Similar to ``ConfigScope`` but can be embedded in another schema.
|
||||||
|
|
||||||
@ -195,15 +220,13 @@ def __init__(
|
|||||||
config:
|
config:
|
||||||
install_tree: $spack/opt/spack
|
install_tree: $spack/opt/spack
|
||||||
"""
|
"""
|
||||||
super().__init__(name, path)
|
super().__init__(name)
|
||||||
self._raw_data: Optional[YamlConfigDict] = None
|
self._raw_data: Optional[YamlConfigDict] = None
|
||||||
self.schema = schema
|
self.schema = schema
|
||||||
|
self.path = path
|
||||||
|
self.writable = writable
|
||||||
self.yaml_path = yaml_path or []
|
self.yaml_path = yaml_path or []
|
||||||
|
|
||||||
@property
|
|
||||||
def is_platform_dependent(self) -> bool:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_section_filename(self, section) -> str:
|
def get_section_filename(self, section) -> str:
|
||||||
return self.path
|
return self.path
|
||||||
|
|
||||||
@ -257,6 +280,8 @@ def get_section(self, section: str) -> Optional[YamlConfigDict]:
|
|||||||
return self.sections.get(section, None)
|
return self.sections.get(section, None)
|
||||||
|
|
||||||
def _write_section(self, section: str) -> None:
|
def _write_section(self, section: str) -> None:
|
||||||
|
if not self.writable:
|
||||||
|
raise ConfigError(f"Cannot write to immutable scope {self}")
|
||||||
data_to_write: Optional[YamlConfigDict] = self._raw_data
|
data_to_write: Optional[YamlConfigDict] = self._raw_data
|
||||||
|
|
||||||
# If there is no existing data, this section SingleFileScope has never
|
# If there is no existing data, this section SingleFileScope has never
|
||||||
@ -301,19 +326,6 @@ def __repr__(self) -> str:
|
|||||||
return f"<SingleFileScope: {self.name}: {self.path}>"
|
return f"<SingleFileScope: {self.name}: {self.path}>"
|
||||||
|
|
||||||
|
|
||||||
class ImmutableConfigScope(ConfigScope):
|
|
||||||
"""A configuration scope that cannot be written to.
|
|
||||||
|
|
||||||
This is used for ConfigScopes passed on the command line.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _write_section(self, section) -> None:
|
|
||||||
raise ConfigError(f"Cannot write to immutable scope {self}")
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<ImmutableConfigScope: {self.name}: {self.path}>"
|
|
||||||
|
|
||||||
|
|
||||||
class InternalConfigScope(ConfigScope):
|
class InternalConfigScope(ConfigScope):
|
||||||
"""An internal configuration scope that is not persisted to a file.
|
"""An internal configuration scope that is not persisted to a file.
|
||||||
|
|
||||||
@ -323,7 +335,7 @@ class InternalConfigScope(ConfigScope):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None:
|
def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None:
|
||||||
super().__init__(name, None)
|
super().__init__(name)
|
||||||
self.sections = syaml.syaml_dict()
|
self.sections = syaml.syaml_dict()
|
||||||
|
|
||||||
if data is not None:
|
if data is not None:
|
||||||
@ -333,9 +345,6 @@ def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None:
|
|||||||
validate({section: dsec}, SECTION_SCHEMAS[section])
|
validate({section: dsec}, SECTION_SCHEMAS[section])
|
||||||
self.sections[section] = _mark_internal(syaml.syaml_dict({section: dsec}), name)
|
self.sections[section] = _mark_internal(syaml.syaml_dict({section: dsec}), name)
|
||||||
|
|
||||||
def get_section_filename(self, section: str) -> str:
|
|
||||||
raise NotImplementedError("Cannot get filename for InternalConfigScope.")
|
|
||||||
|
|
||||||
def get_section(self, section: str) -> Optional[YamlConfigDict]:
|
def get_section(self, section: str) -> Optional[YamlConfigDict]:
|
||||||
"""Just reads from an internal dictionary."""
|
"""Just reads from an internal dictionary."""
|
||||||
if section not in self.sections:
|
if section not in self.sections:
|
||||||
@ -440,27 +449,21 @@ def remove_scope(self, scope_name: str) -> Optional[ConfigScope]:
|
|||||||
return scope
|
return scope
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def file_scopes(self) -> List[ConfigScope]:
|
def writable_scopes(self) -> Generator[ConfigScope, None, None]:
|
||||||
"""List of writable scopes with an associated file."""
|
"""Generator of writable scopes with an associated file."""
|
||||||
return [
|
return (s for s in self.scopes.values() if s.writable)
|
||||||
s
|
|
||||||
for s in self.scopes.values()
|
|
||||||
if (type(s) is ConfigScope or type(s) is SingleFileScope)
|
|
||||||
]
|
|
||||||
|
|
||||||
def highest_precedence_scope(self) -> ConfigScope:
|
def highest_precedence_scope(self) -> ConfigScope:
|
||||||
"""Non-internal scope with highest precedence."""
|
"""Writable scope with highest precedence."""
|
||||||
return next(reversed(self.file_scopes))
|
return next(s for s in reversed(self.scopes.values()) if s.writable) # type: ignore
|
||||||
|
|
||||||
def highest_precedence_non_platform_scope(self) -> ConfigScope:
|
def highest_precedence_non_platform_scope(self) -> ConfigScope:
|
||||||
"""Non-internal non-platform scope with highest precedence
|
"""Writable non-platform scope with highest precedence"""
|
||||||
|
return next(
|
||||||
Platform-specific scopes are of the form scope/platform"""
|
s
|
||||||
generator = reversed(self.file_scopes)
|
for s in reversed(self.scopes.values()) # type: ignore
|
||||||
highest = next(generator)
|
if s.writable and not s.is_platform_dependent
|
||||||
while highest and highest.is_platform_dependent:
|
)
|
||||||
highest = next(generator)
|
|
||||||
return highest
|
|
||||||
|
|
||||||
def matching_scopes(self, reg_expr) -> List[ConfigScope]:
|
def matching_scopes(self, reg_expr) -> List[ConfigScope]:
|
||||||
"""
|
"""
|
||||||
@ -755,13 +758,14 @@ def override(
|
|||||||
|
|
||||||
|
|
||||||
def _add_platform_scope(
|
def _add_platform_scope(
|
||||||
cfg: Union[Configuration, lang.Singleton], scope_type: Type[ConfigScope], name: str, path: str
|
cfg: Union[Configuration, lang.Singleton], name: str, path: str, writable: bool = True
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add a platform-specific subdirectory for the current platform."""
|
"""Add a platform-specific subdirectory for the current platform."""
|
||||||
platform = spack.platforms.host().name
|
platform = spack.platforms.host().name
|
||||||
plat_name = os.path.join(name, platform)
|
scope = DirectoryConfigScope(
|
||||||
plat_path = os.path.join(path, platform)
|
f"{name}/{platform}", os.path.join(path, platform), writable=writable
|
||||||
cfg.push_scope(scope_type(plat_name, plat_path))
|
)
|
||||||
|
cfg.push_scope(scope)
|
||||||
|
|
||||||
|
|
||||||
def config_paths_from_entry_points() -> List[Tuple[str, str]]:
|
def config_paths_from_entry_points() -> List[Tuple[str, str]]:
|
||||||
@ -806,8 +810,8 @@ def _add_command_line_scopes(
|
|||||||
|
|
||||||
# name based on order on the command line
|
# name based on order on the command line
|
||||||
name = f"cmd_scope_{i:d}"
|
name = f"cmd_scope_{i:d}"
|
||||||
cfg.push_scope(ImmutableConfigScope(name, path))
|
cfg.push_scope(DirectoryConfigScope(name, path, writable=False))
|
||||||
_add_platform_scope(cfg, ImmutableConfigScope, name, path)
|
_add_platform_scope(cfg, name, path, writable=False)
|
||||||
|
|
||||||
|
|
||||||
def create() -> Configuration:
|
def create() -> Configuration:
|
||||||
@ -851,10 +855,10 @@ def create() -> Configuration:
|
|||||||
|
|
||||||
# add each scope and its platform-specific directory
|
# add each scope and its platform-specific directory
|
||||||
for name, path in configuration_paths:
|
for name, path in configuration_paths:
|
||||||
cfg.push_scope(ConfigScope(name, path))
|
cfg.push_scope(DirectoryConfigScope(name, path))
|
||||||
|
|
||||||
# Each scope can have per-platfom overrides in subdirectories
|
# Each scope can have per-platfom overrides in subdirectories
|
||||||
_add_platform_scope(cfg, ConfigScope, name, path)
|
_add_platform_scope(cfg, name, path)
|
||||||
|
|
||||||
# add command-line scopes
|
# add command-line scopes
|
||||||
_add_command_line_scopes(cfg, COMMAND_LINE_SCOPES)
|
_add_command_line_scopes(cfg, COMMAND_LINE_SCOPES)
|
||||||
@ -969,7 +973,7 @@ def set(path: str, value: Any, scope: Optional[str] = None) -> None:
|
|||||||
def add_default_platform_scope(platform: str) -> None:
|
def add_default_platform_scope(platform: str) -> None:
|
||||||
plat_name = os.path.join("defaults", platform)
|
plat_name = os.path.join("defaults", platform)
|
||||||
plat_path = os.path.join(CONFIGURATION_DEFAULTS_PATH[1], platform)
|
plat_path = os.path.join(CONFIGURATION_DEFAULTS_PATH[1], platform)
|
||||||
CONFIG.push_scope(ConfigScope(plat_name, plat_path))
|
CONFIG.push_scope(DirectoryConfigScope(plat_name, plat_path))
|
||||||
|
|
||||||
|
|
||||||
def scopes() -> Dict[str, ConfigScope]:
|
def scopes() -> Dict[str, ConfigScope]:
|
||||||
@ -978,19 +982,10 @@ def scopes() -> Dict[str, ConfigScope]:
|
|||||||
|
|
||||||
|
|
||||||
def writable_scopes() -> List[ConfigScope]:
|
def writable_scopes() -> List[ConfigScope]:
|
||||||
"""
|
"""Return list of writable scopes. Higher-priority scopes come first in the list."""
|
||||||
Return list of writable scopes. Higher-priority scopes come first in the
|
scopes = [x for x in CONFIG.scopes.values() if x.writable]
|
||||||
list.
|
scopes.reverse()
|
||||||
"""
|
return scopes
|
||||||
return list(
|
|
||||||
reversed(
|
|
||||||
list(
|
|
||||||
x
|
|
||||||
for x in CONFIG.scopes.values()
|
|
||||||
if not isinstance(x, (InternalConfigScope, ImmutableConfigScope))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def writable_scope_names() -> List[str]:
|
def writable_scope_names() -> List[str]:
|
||||||
@ -1599,7 +1594,7 @@ def _config_from(scopes_or_paths: List[Union[ConfigScope, str]]) -> Configuratio
|
|||||||
path = os.path.normpath(scope_or_path)
|
path = os.path.normpath(scope_or_path)
|
||||||
assert os.path.isdir(path), f'"{path}" must be a directory'
|
assert os.path.isdir(path), f'"{path}" must be a directory'
|
||||||
name = os.path.basename(path)
|
name = os.path.basename(path)
|
||||||
scopes.append(ConfigScope(name, path))
|
scopes.append(DirectoryConfigScope(name, path))
|
||||||
|
|
||||||
configuration = Configuration(*scopes)
|
configuration = Configuration(*scopes)
|
||||||
return configuration
|
return configuration
|
||||||
|
@ -3028,7 +3028,7 @@ def included_config_scopes(self) -> List[spack.config.ConfigScope]:
|
|||||||
SpackEnvironmentError: if the manifest includes a remote file but
|
SpackEnvironmentError: if the manifest includes a remote file but
|
||||||
no configuration stage directory has been identified
|
no configuration stage directory has been identified
|
||||||
"""
|
"""
|
||||||
scopes = []
|
scopes: List[spack.config.ConfigScope] = []
|
||||||
|
|
||||||
# load config scopes added via 'include:', in reverse so that
|
# load config scopes added via 'include:', in reverse so that
|
||||||
# highest-precedence scopes are last.
|
# highest-precedence scopes are last.
|
||||||
@ -3097,23 +3097,21 @@ def included_config_scopes(self) -> List[spack.config.ConfigScope]:
|
|||||||
if os.path.isdir(config_path):
|
if os.path.isdir(config_path):
|
||||||
# directories are treated as regular ConfigScopes
|
# directories are treated as regular ConfigScopes
|
||||||
config_name = "env:%s:%s" % (env_name, os.path.basename(config_path))
|
config_name = "env:%s:%s" % (env_name, os.path.basename(config_path))
|
||||||
tty.debug("Creating ConfigScope {0} for '{1}'".format(config_name, config_path))
|
tty.debug(f"Creating DirectoryConfigScope {config_name} for '{config_path}'")
|
||||||
scope = spack.config.ConfigScope(config_name, config_path)
|
scopes.append(spack.config.DirectoryConfigScope(config_name, config_path))
|
||||||
elif os.path.exists(config_path):
|
elif os.path.exists(config_path):
|
||||||
# files are assumed to be SingleFileScopes
|
# files are assumed to be SingleFileScopes
|
||||||
config_name = "env:%s:%s" % (env_name, config_path)
|
config_name = "env:%s:%s" % (env_name, config_path)
|
||||||
tty.debug(
|
tty.debug(f"Creating SingleFileScope {config_name} for '{config_path}'")
|
||||||
"Creating SingleFileScope {0} for '{1}'".format(config_name, config_path)
|
scopes.append(
|
||||||
)
|
spack.config.SingleFileScope(
|
||||||
scope = spack.config.SingleFileScope(
|
config_name, config_path, spack.schema.merged.schema
|
||||||
config_name, config_path, spack.schema.merged.schema
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
missing.append(config_path)
|
missing.append(config_path)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
scopes.append(scope)
|
|
||||||
|
|
||||||
if missing:
|
if missing:
|
||||||
msg = "Detected {0} missing include path(s):".format(len(missing))
|
msg = "Detected {0} missing include path(s):".format(len(missing))
|
||||||
msg += "\n {0}".format("\n ".join(missing))
|
msg += "\n {0}".format("\n ".join(missing))
|
||||||
@ -3130,7 +3128,10 @@ def env_config_scopes(self) -> List[spack.config.ConfigScope]:
|
|||||||
scopes: List[spack.config.ConfigScope] = [
|
scopes: List[spack.config.ConfigScope] = [
|
||||||
*self.included_config_scopes,
|
*self.included_config_scopes,
|
||||||
spack.config.SingleFileScope(
|
spack.config.SingleFileScope(
|
||||||
self.scope_name, str(self.manifest_file), spack.schema.env.schema, [TOP_LEVEL_KEY]
|
self.scope_name,
|
||||||
|
str(self.manifest_file),
|
||||||
|
spack.schema.env.schema,
|
||||||
|
yaml_path=[TOP_LEVEL_KEY],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
ensure_no_disallowed_env_config_mods(scopes)
|
ensure_no_disallowed_env_config_mods(scopes)
|
||||||
|
@ -115,8 +115,8 @@ def default_config(tmpdir, config_directory, monkeypatch, install_mockery_mutabl
|
|||||||
|
|
||||||
cfg = spack.config.Configuration(
|
cfg = spack.config.Configuration(
|
||||||
*[
|
*[
|
||||||
spack.config.ConfigScope(name, str(mutable_dir))
|
spack.config.DirectoryConfigScope(name, str(mutable_dir))
|
||||||
for name in ["site/%s" % platform.system().lower(), "site", "user"]
|
for name in [f"site/{platform.system().lower()}", "site", "user"]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -774,7 +774,7 @@ def test_keys_are_ordered(configuration_dir):
|
|||||||
"./",
|
"./",
|
||||||
)
|
)
|
||||||
|
|
||||||
config_scope = spack.config.ConfigScope("modules", configuration_dir.join("site"))
|
config_scope = spack.config.DirectoryConfigScope("modules", configuration_dir.join("site"))
|
||||||
|
|
||||||
data = config_scope.get_section("modules")
|
data = config_scope.get_section("modules")
|
||||||
|
|
||||||
@ -956,7 +956,7 @@ def test_immutable_scope(tmpdir):
|
|||||||
root: dummy_tree_value
|
root: dummy_tree_value
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
scope = spack.config.ImmutableConfigScope("test", str(tmpdir))
|
scope = spack.config.DirectoryConfigScope("test", str(tmpdir), writable=False)
|
||||||
|
|
||||||
data = scope.get_section("config")
|
data = scope.get_section("config")
|
||||||
assert data["config"]["install_tree"] == {"root": "dummy_tree_value"}
|
assert data["config"]["install_tree"] == {"root": "dummy_tree_value"}
|
||||||
@ -966,7 +966,9 @@ def test_immutable_scope(tmpdir):
|
|||||||
|
|
||||||
|
|
||||||
def test_single_file_scope(config, env_yaml):
|
def test_single_file_scope(config, env_yaml):
|
||||||
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"])
|
scope = spack.config.SingleFileScope(
|
||||||
|
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
|
||||||
|
)
|
||||||
|
|
||||||
with spack.config.override(scope):
|
with spack.config.override(scope):
|
||||||
# from the single-file config
|
# from the single-file config
|
||||||
@ -1002,7 +1004,9 @@ def test_single_file_scope_section_override(tmpdir, config):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"])
|
scope = spack.config.SingleFileScope(
|
||||||
|
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
|
||||||
|
)
|
||||||
|
|
||||||
with spack.config.override(scope):
|
with spack.config.override(scope):
|
||||||
# from the single-file config
|
# from the single-file config
|
||||||
@ -1018,7 +1022,7 @@ def test_single_file_scope_section_override(tmpdir, config):
|
|||||||
def test_write_empty_single_file_scope(tmpdir):
|
def test_write_empty_single_file_scope(tmpdir):
|
||||||
env_schema = spack.schema.env.schema
|
env_schema = spack.schema.env.schema
|
||||||
scope = spack.config.SingleFileScope(
|
scope = spack.config.SingleFileScope(
|
||||||
"test", str(tmpdir.ensure("config.yaml")), env_schema, ["spack"]
|
"test", str(tmpdir.ensure("config.yaml")), env_schema, yaml_path=["spack"]
|
||||||
)
|
)
|
||||||
scope._write_section("config")
|
scope._write_section("config")
|
||||||
# confirm we can write empty config
|
# confirm we can write empty config
|
||||||
@ -1217,7 +1221,9 @@ def test_license_dir_config(mutable_config, mock_packages):
|
|||||||
|
|
||||||
@pytest.mark.regression("22547")
|
@pytest.mark.regression("22547")
|
||||||
def test_single_file_scope_cache_clearing(env_yaml):
|
def test_single_file_scope_cache_clearing(env_yaml):
|
||||||
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"])
|
scope = spack.config.SingleFileScope(
|
||||||
|
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
|
||||||
|
)
|
||||||
# Check that we can retrieve data from the single file scope
|
# Check that we can retrieve data from the single file scope
|
||||||
before = scope.get_section("config")
|
before = scope.get_section("config")
|
||||||
assert before
|
assert before
|
||||||
|
@ -719,9 +719,9 @@ def _create_mock_configuration_scopes(configuration_dir):
|
|||||||
"""Create the configuration scopes used in `config` and `mutable_config`."""
|
"""Create the configuration scopes used in `config` and `mutable_config`."""
|
||||||
return [
|
return [
|
||||||
spack.config.InternalConfigScope("_builtin", spack.config.CONFIG_DEFAULTS),
|
spack.config.InternalConfigScope("_builtin", spack.config.CONFIG_DEFAULTS),
|
||||||
spack.config.ConfigScope("site", str(configuration_dir.join("site"))),
|
spack.config.DirectoryConfigScope("site", str(configuration_dir.join("site"))),
|
||||||
spack.config.ConfigScope("system", str(configuration_dir.join("system"))),
|
spack.config.DirectoryConfigScope("system", str(configuration_dir.join("system"))),
|
||||||
spack.config.ConfigScope("user", str(configuration_dir.join("user"))),
|
spack.config.DirectoryConfigScope("user", str(configuration_dir.join("user"))),
|
||||||
spack.config.InternalConfigScope("command_line"),
|
spack.config.InternalConfigScope("command_line"),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -755,7 +755,7 @@ def mutable_empty_config(tmpdir_factory, configuration_dir):
|
|||||||
"""Empty configuration that can be modified by the tests."""
|
"""Empty configuration that can be modified by the tests."""
|
||||||
mutable_dir = tmpdir_factory.mktemp("mutable_config").join("tmp")
|
mutable_dir = tmpdir_factory.mktemp("mutable_config").join("tmp")
|
||||||
scopes = [
|
scopes = [
|
||||||
spack.config.ConfigScope(name, str(mutable_dir.join(name)))
|
spack.config.DirectoryConfigScope(name, str(mutable_dir.join(name)))
|
||||||
for name in ["site", "system", "user"]
|
for name in ["site", "system", "user"]
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -790,7 +790,7 @@ def concretize_scope(mutable_config, tmpdir):
|
|||||||
"""Adds a scope for concretization preferences"""
|
"""Adds a scope for concretization preferences"""
|
||||||
tmpdir.ensure_dir("concretize")
|
tmpdir.ensure_dir("concretize")
|
||||||
mutable_config.push_scope(
|
mutable_config.push_scope(
|
||||||
spack.config.ConfigScope("concretize", str(tmpdir.join("concretize")))
|
spack.config.DirectoryConfigScope("concretize", str(tmpdir.join("concretize")))
|
||||||
)
|
)
|
||||||
|
|
||||||
yield str(tmpdir.join("concretize"))
|
yield str(tmpdir.join("concretize"))
|
||||||
@ -802,10 +802,10 @@ def concretize_scope(mutable_config, tmpdir):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def no_compilers_yaml(mutable_config):
|
def no_compilers_yaml(mutable_config):
|
||||||
"""Creates a temporary configuration without compilers.yaml"""
|
"""Creates a temporary configuration without compilers.yaml"""
|
||||||
for scope, local_config in mutable_config.scopes.items():
|
for local_config in mutable_config.scopes.values():
|
||||||
if not local_config.path: # skip internal scopes
|
if not isinstance(local_config, spack.config.DirectoryConfigScope):
|
||||||
continue
|
continue
|
||||||
compilers_yaml = os.path.join(local_config.path, "compilers.yaml")
|
compilers_yaml = local_config.get_section_filename("compilers")
|
||||||
if os.path.exists(compilers_yaml):
|
if os.path.exists(compilers_yaml):
|
||||||
os.remove(compilers_yaml)
|
os.remove(compilers_yaml)
|
||||||
return mutable_config
|
return mutable_config
|
||||||
@ -814,7 +814,9 @@ def no_compilers_yaml(mutable_config):
|
|||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def mock_low_high_config(tmpdir):
|
def mock_low_high_config(tmpdir):
|
||||||
"""Mocks two configuration scopes: 'low' and 'high'."""
|
"""Mocks two configuration scopes: 'low' and 'high'."""
|
||||||
scopes = [spack.config.ConfigScope(name, str(tmpdir.join(name))) for name in ["low", "high"]]
|
scopes = [
|
||||||
|
spack.config.DirectoryConfigScope(name, str(tmpdir.join(name))) for name in ["low", "high"]
|
||||||
|
]
|
||||||
|
|
||||||
with spack.config.use_configuration(*scopes) as config:
|
with spack.config.use_configuration(*scopes) as config:
|
||||||
yield config
|
yield config
|
||||||
|
Loading…
Reference in New Issue
Block a user