summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/config.py67
-rw-r--r--lib/spack/spack/test/cmd/module.py7
-rw-r--r--lib/spack/spack/test/conftest.py68
3 files changed, 78 insertions, 64 deletions
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index 84d8e8ca3f..6067d65fff 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -29,6 +29,7 @@ schemas are in submodules of :py:mod:`spack.schema`.
"""
import collections
+import contextlib
import copy
import functools
import os
@@ -48,6 +49,7 @@ from llnl.util.filesystem import mkdirp
import spack.paths
import spack.architecture
+import spack.compilers
import spack.schema
import spack.schema.compilers
import spack.schema.mirrors
@@ -803,22 +805,6 @@ def _config():
config = llnl.util.lang.Singleton(_config)
-def replace_config(configuration):
- """Replace the current global configuration with the instance passed as
- argument.
-
- Args:
- configuration (Configuration): the new configuration to be used.
-
- Returns:
- The old configuration that has been removed
- """
- global config
- config.clear_caches(), configuration.clear_caches()
- old_config, config = config, configuration
- return old_config
-
-
def get(path, default=None, scope=None):
"""Module-level wrapper for ``Configuration.get()``."""
return config.get(path, default, scope)
@@ -1133,6 +1119,55 @@ def ensure_latest_format_fn(section):
return update_fn
+@contextlib.contextmanager
+def use_configuration(*scopes_or_paths):
+ """Use the configuration scopes passed as arguments within the
+ context manager.
+
+ Args:
+ *scopes_or_paths: scope objects or paths to be used
+
+ Returns:
+ Configuration object associated with the scopes passed as arguments
+ """
+ global config
+
+ # Normalize input and construct a Configuration object
+ configuration = _config_from(scopes_or_paths)
+ config.clear_caches(), configuration.clear_caches()
+
+ # Save and clear the current compiler cache
+ saved_compiler_cache = spack.compilers._cache_config_file
+ spack.compilers._cache_config_file = []
+
+ saved_config, config = config, configuration
+
+ yield configuration
+
+ # Restore previous config files
+ spack.compilers._cache_config_file = saved_compiler_cache
+ config = saved_config
+
+
+@llnl.util.lang.memoized
+def _config_from(scopes_or_paths):
+ scopes = []
+ for scope_or_path in scopes_or_paths:
+ # If we have a config scope we are already done
+ if isinstance(scope_or_path, ConfigScope):
+ scopes.append(scope_or_path)
+ continue
+
+ # Otherwise we need to construct it
+ path = os.path.normpath(scope_or_path)
+ assert os.path.isdir(path), '"{0}" must be a directory'.format(path)
+ name = os.path.basename(path)
+ scopes.append(ConfigScope(name, path))
+
+ configuration = Configuration(*scopes)
+ return configuration
+
+
class ConfigError(SpackError):
"""Superclass for all Spack config related errors."""
diff --git a/lib/spack/spack/test/cmd/module.py b/lib/spack/spack/test/cmd/module.py
index a488c47d1c..8be6c129c7 100644
--- a/lib/spack/spack/test/cmd/module.py
+++ b/lib/spack/spack/test/cmd/module.py
@@ -8,10 +8,10 @@ import re
import pytest
+import spack.config
import spack.main
import spack.modules
import spack.store
-from spack.test.conftest import use_configuration
module = spack.main.SpackCommand('module')
@@ -19,11 +19,12 @@ module = spack.main.SpackCommand('module')
#: make sure module files are generated for all the tests here
@pytest.fixture(scope='module', autouse=True)
def ensure_module_files_are_there(
- mock_repo_path, mock_store, mock_configuration):
+ mock_repo_path, mock_store, mock_configuration_scopes
+):
"""Generate module files for module tests."""
module = spack.main.SpackCommand('module')
with spack.store.use_store(mock_store):
- with use_configuration(mock_configuration):
+ with spack.config.use_configuration(*mock_configuration_scopes):
with spack.repo.use_repositories(mock_repo_path):
module('tcl', 'refresh', '-y')
diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py
index 153bee128f..5b1e7b83e6 100644
--- a/lib/spack/spack/test/conftest.py
+++ b/lib/spack/spack/test/conftest.py
@@ -4,7 +4,6 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import collections
-import contextlib
import errno
import inspect
import itertools
@@ -336,7 +335,7 @@ spack.config.config = spack.config._config()
#
-# Context managers used by fixtures
+# Note on context managers used by fixtures
#
# Because these context managers modify global state, they should really
# ONLY be used persistently (i.e., around yield statements) in
@@ -357,23 +356,6 @@ spack.config.config = spack.config._config()
# *USE*, or things can get really confusing.
#
-@contextlib.contextmanager
-def use_configuration(config):
- """Context manager to swap out the global Spack configuration."""
- saved = spack.config.replace_config(config)
-
- # Avoid using real spack configuration that has been cached by other
- # tests, and avoid polluting the cache with spack test configuration
- # (including modified configuration)
- saved_compiler_cache = spack.compilers._cache_config_file
- spack.compilers._cache_config_file = []
-
- yield
-
- spack.config.replace_config(saved)
- spack.compilers._cache_config_file = saved_compiler_cache
-
-
#
# Test-specific fixtures
#
@@ -430,9 +412,7 @@ def default_config():
This ensures we can test the real default configuration without having
tests fail when the user overrides the defaults that we test against."""
defaults_path = os.path.join(spack.paths.etc_path, 'spack', 'defaults')
- defaults_scope = spack.config.ConfigScope('defaults', defaults_path)
- defaults_config = spack.config.Configuration(defaults_scope)
- with use_configuration(defaults_config):
+ with spack.config.use_configuration(defaults_path) as defaults_config:
yield defaults_config
@@ -508,7 +488,7 @@ def configuration_dir(tmpdir_factory, linux_os):
@pytest.fixture(scope='session')
-def mock_configuration(configuration_dir):
+def mock_configuration_scopes(configuration_dir):
"""Create a persistent Configuration object from the configuration_dir."""
defaults = spack.config.InternalConfigScope(
'_builtin', spack.config.config_defaults
@@ -519,14 +499,14 @@ def mock_configuration(configuration_dir):
for name in ['site', 'system', 'user']]
test_scopes.append(spack.config.InternalConfigScope('command_line'))
- yield spack.config.Configuration(*test_scopes)
+ yield test_scopes
@pytest.fixture(scope='function')
-def config(mock_configuration):
+def config(mock_configuration_scopes):
"""This fixture activates/deactivates the mock configuration."""
- with use_configuration(mock_configuration):
- yield mock_configuration
+ with spack.config.use_configuration(*mock_configuration_scopes) as config:
+ yield config
@pytest.fixture(scope='function')
@@ -535,11 +515,10 @@ def mutable_config(tmpdir_factory, configuration_dir):
mutable_dir = tmpdir_factory.mktemp('mutable_config').join('tmp')
configuration_dir.copy(mutable_dir)
- cfg = spack.config.Configuration(
- *[spack.config.ConfigScope(name, str(mutable_dir.join(name)))
- for name in ['site', 'system', 'user']])
+ scopes = [spack.config.ConfigScope(name, str(mutable_dir.join(name)))
+ for name in ['site', 'system', 'user']]
- with use_configuration(cfg):
+ with spack.config.use_configuration(*scopes) as cfg:
yield cfg
@@ -547,23 +526,20 @@ def mutable_config(tmpdir_factory, configuration_dir):
def mutable_empty_config(tmpdir_factory, configuration_dir):
"""Empty configuration that can be modified by the tests."""
mutable_dir = tmpdir_factory.mktemp('mutable_config').join('tmp')
+ scopes = [spack.config.ConfigScope(name, str(mutable_dir.join(name)))
+ for name in ['site', 'system', 'user']]
- cfg = spack.config.Configuration(
- *[spack.config.ConfigScope(name, str(mutable_dir.join(name)))
- for name in ['site', 'system', 'user']])
-
- with use_configuration(cfg):
+ with spack.config.use_configuration(*scopes) as cfg:
yield cfg
@pytest.fixture()
def mock_low_high_config(tmpdir):
"""Mocks two configuration scopes: 'low' and 'high'."""
- config = spack.config.Configuration(
- *[spack.config.ConfigScope(name, str(tmpdir.join(name)))
- for name in ['low', 'high']])
+ scopes = [spack.config.ConfigScope(name, str(tmpdir.join(name)))
+ for name in ['low', 'high']]
- with use_configuration(config):
+ with spack.config.use_configuration(*scopes) as config:
yield config
@@ -612,7 +588,7 @@ def _store_dir_and_cache(tmpdir_factory):
@pytest.fixture(scope='session')
-def mock_store(tmpdir_factory, mock_repo_path, mock_configuration,
+def mock_store(tmpdir_factory, mock_repo_path, mock_configuration_scopes,
_store_dir_and_cache):
"""Creates a read-only mock database with some packages installed note
that the ref count for dyninst here will be 3, as it's recycled
@@ -626,7 +602,7 @@ def mock_store(tmpdir_factory, mock_repo_path, mock_configuration,
# If the cache does not exist populate the store and create it
if not os.path.exists(str(store_cache.join('.spack-db'))):
- with use_configuration(mock_configuration):
+ with spack.config.use_configuration(*mock_configuration_scopes):
with spack.store.use_store(str(store_path)) as store:
with spack.repo.use_repositories(mock_repo_path):
_populate(store.db)
@@ -641,8 +617,10 @@ def mock_store(tmpdir_factory, mock_repo_path, mock_configuration,
@pytest.fixture(scope='function')
-def mutable_mock_store(tmpdir_factory, mock_repo_path, mock_configuration,
- _store_dir_and_cache):
+def mutable_mock_store(
+ tmpdir_factory, mock_repo_path, mock_configuration_scopes,
+ _store_dir_and_cache
+):
"""Creates a read-only mock database with some packages installed note
that the ref count for dyninst here will be 3, as it's recycled
across each install.
@@ -655,7 +633,7 @@ def mutable_mock_store(tmpdir_factory, mock_repo_path, mock_configuration,
# If the cache does not exist populate the store and create it
if not os.path.exists(str(store_cache.join('.spack-db'))):
- with use_configuration(mock_configuration):
+ with spack.config.use_configuration(*mock_configuration_scopes):
with spack.store.use_store(str(store_path)) as store:
with spack.repo.use_repositories(mock_repo_path):
_populate(store.db)