Allow users to specify root env dir
Environments managed by spack have some advantages over anonymous Environments but they are tucked away inside spack's directory tree. This PR gives users the ability to specify where the environments should live. See #32823
This commit is contained in:
parent
c25b7ea898
commit
3f2e77e5fa
@ -76,6 +76,10 @@ config:
|
||||
source_cache: $spack/var/spack/cache
|
||||
|
||||
|
||||
## Directory where spack managed environments are created and stored
|
||||
environments_root: $spack/var/spack/environments
|
||||
|
||||
|
||||
# Cache directory for miscellaneous files, like the package index.
|
||||
# This can be purged with `spack clean --misc-cache`
|
||||
misc_cache: $user_cache_path/cache
|
||||
|
@ -63,7 +63,10 @@
|
||||
|
||||
|
||||
#: path where environments are stored in the spack tree
|
||||
env_path = os.path.join(spack.paths.var_path, "environments")
|
||||
# circular dependency to use canonicalize_path but we want to ignore an active env anyways
|
||||
# env_path = spack.config.get(os.path.expandvars(os.path.expanduser("config:environments_root")))
|
||||
def env_path():
|
||||
return spack.util.path.canonicalize_path(spack.config.get("config:environments_root"), False)
|
||||
|
||||
|
||||
#: Name of the input yaml file for an environment
|
||||
@ -205,7 +208,7 @@ def active_environment():
|
||||
|
||||
def _root(name):
|
||||
"""Non-validating version of root(), to be used internally."""
|
||||
return os.path.join(env_path, name)
|
||||
return os.path.join(env_path(), name)
|
||||
|
||||
|
||||
def root(name):
|
||||
@ -257,10 +260,10 @@ def all_environment_names():
|
||||
"""List the names of environments that currently exist."""
|
||||
# just return empty if the env path does not exist. A read-only
|
||||
# operation like list should not try to create a directory.
|
||||
if not os.path.exists(env_path):
|
||||
if not os.path.exists(env_path()):
|
||||
return []
|
||||
|
||||
candidates = sorted(os.listdir(env_path))
|
||||
candidates = sorted(os.listdir(env_path()))
|
||||
names = []
|
||||
for candidate in candidates:
|
||||
yaml_path = os.path.join(_root(candidate), manifest_name)
|
||||
@ -842,7 +845,7 @@ def clear(self, re_read=False):
|
||||
@property
|
||||
def internal(self):
|
||||
"""Whether this environment is managed by Spack."""
|
||||
return self.path.startswith(env_path)
|
||||
return self.path.startswith(env_path())
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -52,6 +52,7 @@
|
||||
"license_dir": {"type": "string"},
|
||||
"source_cache": {"type": "string"},
|
||||
"misc_cache": {"type": "string"},
|
||||
"environments_root": {"type": "string"},
|
||||
"connect_timeout": {"type": "integer", "minimum": 0},
|
||||
"verify_ssl": {"type": "boolean"},
|
||||
"suppress_gpg_warnings": {"type": "boolean"},
|
||||
|
@ -28,6 +28,9 @@
|
||||
import spack.schema.repos
|
||||
import spack.util.path as spack_path
|
||||
import spack.util.spack_yaml as syaml
|
||||
from spack.main import SpackCommand
|
||||
|
||||
env = SpackCommand("env")
|
||||
|
||||
# sample config data
|
||||
config_low = {
|
||||
@ -1005,6 +1008,7 @@ def test_good_env_yaml(tmpdir):
|
||||
config:
|
||||
verify_ssl: False
|
||||
dirty: False
|
||||
environtments_dir: ~/my/env/location
|
||||
repos:
|
||||
- ~/my/repo/location
|
||||
mirrors:
|
||||
@ -1431,3 +1435,18 @@ def test_config_file_read_invalid_yaml(tmpdir, mutable_empty_config):
|
||||
|
||||
with pytest.raises(spack.config.ConfigFileError, match="parsing yaml"):
|
||||
spack.config.read_config_file(filename)
|
||||
|
||||
|
||||
def test_environment_created_in_users_location(mutable_config, tmpdir):
|
||||
"""Test that an environment is created in a location based on the config"""
|
||||
spack.config.set("config:environments_root", str(tmpdir.join("envs")))
|
||||
env_dir = spack.config.get("config:environments_root")
|
||||
assert tmpdir.strpath in env_dir
|
||||
assert not os.path.isdir(env_dir)
|
||||
os.makedirs(env_dir)
|
||||
env('create', 'test')
|
||||
out = env('list')
|
||||
assert 'test' in out
|
||||
|
||||
assert env_dir in ev.root('test')
|
||||
assert os.path.isdir(os.path.join(env_dir, 'test'))
|
||||
|
@ -1493,11 +1493,13 @@ def get_rev():
|
||||
@pytest.fixture()
|
||||
def mutable_mock_env_path(tmpdir_factory):
|
||||
"""Fixture for mocking the internal spack environments directory."""
|
||||
saved_path = ev.environment.env_path
|
||||
saved_path_fun = ev.environment.env_path
|
||||
mock_path = tmpdir_factory.mktemp("mock-env-path")
|
||||
ev.environment.env_path = str(mock_path)
|
||||
def mock_fun():
|
||||
return str(mock_path)
|
||||
ev.environment.env_path = mock_fun
|
||||
yield mock_path
|
||||
ev.environment.env_path = saved_path
|
||||
ev.environment.env_path = saved_path_fun
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
@ -226,7 +226,7 @@ def convert_to_platform_path(path):
|
||||
return format_os_path(path, mode=Path.platform_path)
|
||||
|
||||
|
||||
def substitute_config_variables(path):
|
||||
def substitute_config_variables(path, allow_env=True):
|
||||
"""Substitute placeholders into paths.
|
||||
|
||||
Spack allows paths in configs to have some placeholders, as follows:
|
||||
@ -242,15 +242,16 @@ def substitute_config_variables(path):
|
||||
replaced if there is an active environment, and should only be used in
|
||||
environment yaml files.
|
||||
"""
|
||||
import spack.environment as ev # break circular
|
||||
|
||||
_replacements = replacements()
|
||||
env = ev.active_environment()
|
||||
if env:
|
||||
_replacements.update({"env": env.path})
|
||||
else:
|
||||
# If a previous invocation added env, remove it
|
||||
_replacements.pop("env", None)
|
||||
if allow_env:
|
||||
import spack.environment as ev # break circular
|
||||
|
||||
env = ev.active_environment()
|
||||
if env:
|
||||
_replacements.update({"env": env.path})
|
||||
else:
|
||||
# If a previous invocation added env, remove it
|
||||
_replacements.pop("env", None)
|
||||
|
||||
# Look up replacements
|
||||
def repl(match):
|
||||
@ -261,9 +262,9 @@ def repl(match):
|
||||
return re.sub(r"(\$\w+\b|\$\{\w+\})", repl, path)
|
||||
|
||||
|
||||
def substitute_path_variables(path):
|
||||
def substitute_path_variables(path, allow_env = True):
|
||||
"""Substitute config vars, expand environment vars, expand user home."""
|
||||
path = substitute_config_variables(path)
|
||||
path = substitute_config_variables(path, allow_env)
|
||||
path = os.path.expandvars(path)
|
||||
path = os.path.expanduser(path)
|
||||
return path
|
||||
@ -305,7 +306,7 @@ def add_padding(path, length):
|
||||
return os.path.join(path, padding)
|
||||
|
||||
|
||||
def canonicalize_path(path):
|
||||
def canonicalize_path(path, allow_env = True):
|
||||
"""Same as substitute_path_variables, but also take absolute path.
|
||||
|
||||
Arguments:
|
||||
@ -321,7 +322,7 @@ def canonicalize_path(path):
|
||||
filename = os.path.dirname(path._start_mark.name)
|
||||
assert path._start_mark.name == path._end_mark.name
|
||||
|
||||
path = substitute_path_variables(path)
|
||||
path = substitute_path_variables(path, allow_env)
|
||||
if not os.path.isabs(path):
|
||||
if filename:
|
||||
path = os.path.join(filename, path)
|
||||
|
Loading…
Reference in New Issue
Block a user