spack -C <env>: use env config w/o activation (#45046)
Precedence: 1. Named environment 2. Anonymous environment 3. Generic directory
This commit is contained in:
parent
aeaa922eef
commit
8a430f89b3
@ -796,22 +796,27 @@ def config_paths_from_entry_points() -> List[Tuple[str, str]]:
|
|||||||
def _add_command_line_scopes(
|
def _add_command_line_scopes(
|
||||||
cfg: Union[Configuration, lang.Singleton], command_line_scopes: List[str]
|
cfg: Union[Configuration, lang.Singleton], command_line_scopes: List[str]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add additional scopes from the --config-scope argument.
|
"""Add additional scopes from the --config-scope argument, either envs or dirs."""
|
||||||
|
import spack.environment.environment as env # circular import
|
||||||
|
|
||||||
Command line scopes are named after their position in the arg list.
|
|
||||||
"""
|
|
||||||
for i, path in enumerate(command_line_scopes):
|
for i, path in enumerate(command_line_scopes):
|
||||||
# We ensure that these scopes exist and are readable, as they are
|
name = f"cmd_scope_{i}"
|
||||||
# provided on the command line by the user.
|
|
||||||
if not os.path.isdir(path):
|
|
||||||
raise ConfigError(f"config scope is not a directory: '{path}'")
|
|
||||||
elif not os.access(path, os.R_OK):
|
|
||||||
raise ConfigError(f"config scope is not readable: '{path}'")
|
|
||||||
|
|
||||||
# name based on order on the command line
|
if env.exists(path): # managed environment
|
||||||
name = f"cmd_scope_{i:d}"
|
manifest = env.EnvironmentManifestFile(env.root(path))
|
||||||
cfg.push_scope(DirectoryConfigScope(name, path, writable=False))
|
elif env.is_env_dir(path): # anonymous environment
|
||||||
_add_platform_scope(cfg, name, path, writable=False)
|
manifest = env.EnvironmentManifestFile(path)
|
||||||
|
elif os.path.isdir(path): # directory with config files
|
||||||
|
cfg.push_scope(DirectoryConfigScope(name, path, writable=False))
|
||||||
|
_add_platform_scope(cfg, name, path, writable=False)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise ConfigError(f"Invalid configuration scope: {path}")
|
||||||
|
|
||||||
|
for scope in manifest.env_config_scopes:
|
||||||
|
scope.name = f"{name}:{scope.name}"
|
||||||
|
scope.writable = False
|
||||||
|
cfg.push_scope(scope)
|
||||||
|
|
||||||
|
|
||||||
def create() -> Configuration:
|
def create() -> Configuration:
|
||||||
|
@ -269,9 +269,7 @@ def root(name):
|
|||||||
|
|
||||||
def exists(name):
|
def exists(name):
|
||||||
"""Whether an environment with this name exists or not."""
|
"""Whether an environment with this name exists or not."""
|
||||||
if not valid_env_name(name):
|
return valid_env_name(name) and os.path.isdir(_root(name))
|
||||||
return False
|
|
||||||
return os.path.isdir(root(name))
|
|
||||||
|
|
||||||
|
|
||||||
def active(name):
|
def active(name):
|
||||||
@ -922,7 +920,7 @@ def __init__(self, manifest_dir: Union[str, pathlib.Path]) -> None:
|
|||||||
def _load_manifest_file(self):
|
def _load_manifest_file(self):
|
||||||
"""Instantiate and load the manifest file contents into memory."""
|
"""Instantiate and load the manifest file contents into memory."""
|
||||||
with lk.ReadTransaction(self.txlock):
|
with lk.ReadTransaction(self.txlock):
|
||||||
self.manifest = EnvironmentManifestFile(self.path)
|
self.manifest = EnvironmentManifestFile(self.path, self.name)
|
||||||
with self.manifest.use_config():
|
with self.manifest.use_config():
|
||||||
self._read()
|
self._read()
|
||||||
|
|
||||||
@ -2753,10 +2751,11 @@ def from_lockfile(manifest_dir: Union[pathlib.Path, str]) -> "EnvironmentManifes
|
|||||||
manifest.flush()
|
manifest.flush()
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
def __init__(self, manifest_dir: Union[pathlib.Path, str]) -> None:
|
def __init__(self, manifest_dir: Union[pathlib.Path, str], name: Optional[str] = None) -> None:
|
||||||
self.manifest_dir = pathlib.Path(manifest_dir)
|
self.manifest_dir = pathlib.Path(manifest_dir)
|
||||||
|
self.name = name or str(manifest_dir)
|
||||||
self.manifest_file = self.manifest_dir / manifest_name
|
self.manifest_file = self.manifest_dir / manifest_name
|
||||||
self.scope_name = f"env:{environment_name(self.manifest_dir)}"
|
self.scope_name = f"env:{self.name}"
|
||||||
self.config_stage_dir = os.path.join(env_subdir_path(manifest_dir), "config")
|
self.config_stage_dir = os.path.join(env_subdir_path(manifest_dir), "config")
|
||||||
|
|
||||||
#: Configuration scopes associated with this environment. Note that these are not
|
#: Configuration scopes associated with this environment. Note that these are not
|
||||||
@ -3033,7 +3032,6 @@ def included_config_scopes(self) -> 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.
|
||||||
includes = self[TOP_LEVEL_KEY].get("include", [])
|
includes = self[TOP_LEVEL_KEY].get("include", [])
|
||||||
env_name = environment_name(self.manifest_dir)
|
|
||||||
missing = []
|
missing = []
|
||||||
for i, config_path in enumerate(reversed(includes)):
|
for i, config_path in enumerate(reversed(includes)):
|
||||||
# allow paths to contain spack config/environment variables, etc.
|
# allow paths to contain spack config/environment variables, etc.
|
||||||
@ -3096,12 +3094,12 @@ 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 = f"env:{self.name}:{os.path.basename(config_path)}"
|
||||||
tty.debug(f"Creating DirectoryConfigScope {config_name} for '{config_path}'")
|
tty.debug(f"Creating DirectoryConfigScope {config_name} for '{config_path}'")
|
||||||
scopes.append(spack.config.DirectoryConfigScope(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 = f"env:{self.name}:{config_path}"
|
||||||
tty.debug(f"Creating SingleFileScope {config_name} for '{config_path}'")
|
tty.debug(f"Creating SingleFileScope {config_name} for '{config_path}'")
|
||||||
scopes.append(
|
scopes.append(
|
||||||
spack.config.SingleFileScope(
|
spack.config.SingleFileScope(
|
||||||
|
@ -444,8 +444,9 @@ def make_argument_parser(**kwargs):
|
|||||||
"--config-scope",
|
"--config-scope",
|
||||||
dest="config_scopes",
|
dest="config_scopes",
|
||||||
action="append",
|
action="append",
|
||||||
metavar="DIR",
|
metavar="DIR|ENV",
|
||||||
help="add a custom configuration scope",
|
help="add directory or environment as read-only configuration scope, without activating "
|
||||||
|
"the environment.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-d",
|
"-d",
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.filesystem import getuid, join_path, mkdirp, touch, touchp
|
from llnl.util.filesystem import join_path, touch, touchp
|
||||||
|
|
||||||
import spack.config
|
import spack.config
|
||||||
import spack.directory_layout
|
import spack.directory_layout
|
||||||
@ -864,26 +864,18 @@ def test_bad_config_section(mock_low_high_config):
|
|||||||
spack.config.get("foobar")
|
spack.config.get("foobar")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.not_on_windows("chmod not supported on Windows")
|
def test_bad_command_line_scopes(tmp_path, config):
|
||||||
@pytest.mark.skipif(getuid() == 0, reason="user is root")
|
|
||||||
def test_bad_command_line_scopes(tmpdir, config):
|
|
||||||
cfg = spack.config.Configuration()
|
cfg = spack.config.Configuration()
|
||||||
|
file_path = tmp_path / "file_instead_of_dir"
|
||||||
|
non_existing_path = tmp_path / "non_existing_dir"
|
||||||
|
|
||||||
with tmpdir.as_cwd():
|
file_path.write_text("")
|
||||||
with pytest.raises(spack.config.ConfigError):
|
|
||||||
spack.config._add_command_line_scopes(cfg, ["bad_path"])
|
|
||||||
|
|
||||||
touch("unreadable_file")
|
with pytest.raises(spack.config.ConfigError):
|
||||||
with pytest.raises(spack.config.ConfigError):
|
spack.config._add_command_line_scopes(cfg, [str(file_path)])
|
||||||
spack.config._add_command_line_scopes(cfg, ["unreadable_file"])
|
|
||||||
|
|
||||||
mkdirp("unreadable_dir")
|
with pytest.raises(spack.config.ConfigError):
|
||||||
with pytest.raises(spack.config.ConfigError):
|
spack.config._add_command_line_scopes(cfg, [str(non_existing_path)])
|
||||||
try:
|
|
||||||
os.chmod("unreadable_dir", 0)
|
|
||||||
spack.config._add_command_line_scopes(cfg, ["unreadable_dir"])
|
|
||||||
finally:
|
|
||||||
os.chmod("unreadable_dir", 0o700) # so tmpdir can be removed
|
|
||||||
|
|
||||||
|
|
||||||
def test_add_command_line_scopes(tmpdir, mutable_config):
|
def test_add_command_line_scopes(tmpdir, mutable_config):
|
||||||
@ -898,6 +890,45 @@ 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)])
|
||||||
|
assert mutable_config.get("config:verify_ssl") is False
|
||||||
|
assert mutable_config.get("config:dirty") is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_command_line_scope_env(tmp_path, mutable_mock_env_path):
|
||||||
|
"""Test whether --config-scope <env> works, either by name or path."""
|
||||||
|
managed_env = ev.create("example").manifest_path
|
||||||
|
|
||||||
|
with open(managed_env, "w") as f:
|
||||||
|
f.write(
|
||||||
|
"""\
|
||||||
|
spack:
|
||||||
|
config:
|
||||||
|
install_tree:
|
||||||
|
root: /tmp/first
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(tmp_path / "spack.yaml", "w") as f:
|
||||||
|
f.write(
|
||||||
|
"""\
|
||||||
|
spack:
|
||||||
|
config:
|
||||||
|
install_tree:
|
||||||
|
root: /tmp/second
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
config = spack.config.Configuration()
|
||||||
|
spack.config._add_command_line_scopes(config, ["example", str(tmp_path)])
|
||||||
|
assert len(config.scopes) == 2
|
||||||
|
assert config.get("config:install_tree:root") == "/tmp/second"
|
||||||
|
|
||||||
|
config = spack.config.Configuration()
|
||||||
|
spack.config._add_command_line_scopes(config, [str(tmp_path), "example"])
|
||||||
|
assert len(config.scopes) == 2
|
||||||
|
assert config.get("config:install_tree:root") == "/tmp/first"
|
||||||
|
|
||||||
|
assert ev.active_environment() is None # shouldn't cause an environment to be activated
|
||||||
|
|
||||||
|
|
||||||
def test_nested_override():
|
def test_nested_override():
|
||||||
|
@ -438,7 +438,7 @@ complete -c spack -n '__fish_spack_using_command ' -l color -r -d 'when to color
|
|||||||
complete -c spack -n '__fish_spack_using_command ' -s c -l config -r -f -a config_vars
|
complete -c spack -n '__fish_spack_using_command ' -s c -l config -r -f -a config_vars
|
||||||
complete -c spack -n '__fish_spack_using_command ' -s c -l config -r -d 'add one or more custom, one off config settings'
|
complete -c spack -n '__fish_spack_using_command ' -s c -l config -r -d 'add one or more custom, one off config settings'
|
||||||
complete -c spack -n '__fish_spack_using_command ' -s C -l config-scope -r -f -a config_scopes
|
complete -c spack -n '__fish_spack_using_command ' -s C -l config-scope -r -f -a config_scopes
|
||||||
complete -c spack -n '__fish_spack_using_command ' -s C -l config-scope -r -d 'add a custom configuration scope'
|
complete -c spack -n '__fish_spack_using_command ' -s C -l config-scope -r -d 'add directory or environment as read-only configuration scope, without activating the environment.'
|
||||||
complete -c spack -n '__fish_spack_using_command ' -s d -l debug -f -a debug
|
complete -c spack -n '__fish_spack_using_command ' -s d -l debug -f -a debug
|
||||||
complete -c spack -n '__fish_spack_using_command ' -s d -l debug -d 'write out debug messages'
|
complete -c spack -n '__fish_spack_using_command ' -s d -l debug -d 'write out debug messages'
|
||||||
complete -c spack -n '__fish_spack_using_command ' -l timestamp -f -a timestamp
|
complete -c spack -n '__fish_spack_using_command ' -l timestamp -f -a timestamp
|
||||||
|
Loading…
Reference in New Issue
Block a user