diff options
author | Massimiliano Culpo <massimiliano.culpo@gmail.com> | 2021-10-06 20:32:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-06 11:32:26 -0700 |
commit | 98ee00b9773e1ce4a644c431feddb3e66a28ae6a (patch) | |
tree | 9084957eca7d6b9dfa6cd67dfa13427885abb035 /lib | |
parent | fdf76ecb519a0bfba7f904beee68e71ca8c49fe7 (diff) | |
download | spack-98ee00b9773e1ce4a644c431feddb3e66a28ae6a.tar.gz spack-98ee00b9773e1ce4a644c431feddb3e66a28ae6a.tar.bz2 spack-98ee00b9773e1ce4a644c431feddb3e66a28ae6a.tar.xz spack-98ee00b9773e1ce4a644c431feddb3e66a28ae6a.zip |
Restore the correct computation of stores in environments (#26560)
Environments push/pop scopes upon activation. If some lazily
evaluated value depending on the current configuration was
computed and cached before the scopes are pushed / popped
there will be an inconsistency in the current state.
This PR fixes the issue for stores, but it would be better
to move away from global state.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/environment/environment.py | 12 | ||||
-rw-r--r-- | lib/spack/spack/store.py | 16 | ||||
-rw-r--r-- | lib/spack/spack/test/bootstrap.py | 22 | ||||
-rw-r--r-- | lib/spack/spack/test/cmd/env.py | 18 |
4 files changed, 66 insertions, 2 deletions
diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index 88dd545398..5a271fc6dd 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -126,7 +126,14 @@ def activate(env, use_env_repo=False): if not isinstance(env, Environment): raise TypeError("`env` should be of type {0}".format(Environment.__name__)) + # Check if we need to reinitialize the store due to pushing the configuration + # below. + store_before_pushing = spack.config.get('config:install_tree') prepare_config_scope(env) + store_after_pushing = spack.config.get('config:install_tree') + if store_before_pushing != store_after_pushing: + # Hack to store the state of the store before activation + env.store_token = spack.store.reinitialize() if use_env_repo: spack.repo.path.put_first(env.repo) @@ -144,6 +151,11 @@ def deactivate(): if not _active_environment: return + # If we attached a store token on activation, restore the previous state + # and consume the token + if hasattr(_active_environment, 'store_token'): + spack.store.restore(_active_environment.store_token) + delattr(_active_environment, 'store_token') deactivate_config_scope(_active_environment) # use _repo so we only remove if a repo was actually constructed diff --git a/lib/spack/spack/store.py b/lib/spack/spack/store.py index c60772e595..b0a418c7e3 100644 --- a/lib/spack/spack/store.py +++ b/lib/spack/spack/store.py @@ -236,17 +236,29 @@ layout = llnl.util.lang.LazyReference(_store_layout) def reinitialize(): - """Restore globals to the same state they would have at start-up""" + """Restore globals to the same state they would have at start-up. Return a token + containing the state of the store before reinitialization. + """ global store global root, unpadded_root, db, layout - store = llnl.util.lang.Singleton(_store) + token = store, root, unpadded_root, db, layout + store = llnl.util.lang.Singleton(_store) root = llnl.util.lang.LazyReference(_store_root) unpadded_root = llnl.util.lang.LazyReference(_store_unpadded_root) db = llnl.util.lang.LazyReference(_store_db) layout = llnl.util.lang.LazyReference(_store_layout) + return token + + +def restore(token): + """Restore the environment from a token returned by reinitialize""" + global store + global root, unpadded_root, db, layout + store, root, unpadded_root, db, layout = token + def retrieve_upstream_dbs(): other_spack_instances = spack.config.get('upstreams', {}) diff --git a/lib/spack/spack/test/bootstrap.py b/lib/spack/spack/test/bootstrap.py index fb84921c7a..99c1a61fd3 100644 --- a/lib/spack/spack/test/bootstrap.py +++ b/lib/spack/spack/test/bootstrap.py @@ -118,3 +118,25 @@ def test_config_yaml_is_preserved_during_bootstrap(mutable_config): with spack.bootstrap.ensure_bootstrap_configuration(): assert spack.config.get('config:test_stage') == expected_dir assert spack.config.get('config:test_stage') == expected_dir + + +@pytest.mark.regression('26548') +def test_custom_store_in_environment(mutable_config, tmpdir): + # Test that the custom store in an environment is taken into account + # during bootstrapping + spack_yaml = tmpdir.join('spack.yaml') + spack_yaml.write(""" +spack: + specs: + - libelf + config: + install_tree: + root: /tmp/store +""") + with spack.environment.Environment(str(tmpdir)): + assert spack.environment.active_environment() + assert spack.config.get('config:install_tree:root') == '/tmp/store' + # Don't trigger evaluation here + with spack.bootstrap.ensure_bootstrap_configuration(): + pass + assert str(spack.store.root) == '/tmp/store' diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index 3d1725a3f0..5c57035527 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -2663,3 +2663,21 @@ def test_activation_and_deactiviation_ambiguities(method, env, no_env, env_dir, method(args) _, err = capsys.readouterr() assert 'is ambiguous' in err + + +@pytest.mark.regression('26548') +def test_custom_store_in_environment(mutable_config, tmpdir): + spack_yaml = tmpdir.join('spack.yaml') + spack_yaml.write(""" +spack: + specs: + - libelf + config: + install_tree: + root: /tmp/store +""") + current_store_root = str(spack.store.root) + assert str(current_store_root) != '/tmp/store' + with spack.environment.Environment(str(tmpdir)): + assert str(spack.store.root) == '/tmp/store' + assert str(spack.store.root) == current_store_root |