Skip to content

Commit

Permalink
tests: cleanup config:build_stage handling (fixes spack#12651, spack#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tldahlgren committed Oct 11, 2019
1 parent 60eb8b8 commit 92d1a1d
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 197 deletions.
5 changes: 4 additions & 1 deletion lib/spack/spack/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@
#: this is shorter and more readable than listing all choices
scopes_metavar = '{defaults,system,site,user}[/PLATFORM]'

#: Base name for the (internal) overrides scope.
overrides_base_name = 'overrides-'


def first_existing(dictionary, keys):
"""Get the value of the first key in keys that is in the dictionary."""
Expand Down Expand Up @@ -549,11 +552,11 @@ def override(path_or_scope, value=None):
an internal config scope for it and push/pop that scope.
"""
base_name = 'overrides-'
if isinstance(path_or_scope, ConfigScope):
overrides = path_or_scope
config.push_scope(path_or_scope)
else:
base_name = overrides_base_name
# Ensure the new override gets a unique scope name
current_overrides = [s.name for s in
config.matching_scopes(r'^{0}'.format(base_name))]
Expand Down
30 changes: 16 additions & 14 deletions lib/spack/spack/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,29 @@ def _first_accessible_path(paths):


def _resolve_paths(candidates):
"""Resolve paths, removing extra $user from $tempdir if needed."""
"""
Resolve candidate paths and make user-related adjustments.
Adjustments involve removing extra $user from $tempdir if $tempdir includes
$user and appending $user if it is not present in the path.
"""
temp_path = sup.canonicalize_path('$tempdir')
tmp_has_usr = getpass.getuser() in temp_path.split(os.path.sep)
user = getpass.getuser()
tmp_has_usr = user in temp_path.split(os.path.sep)

paths = []
for path in candidates:
# First remove the extra `$user` node from a `$tempdir/$user` entry
# for hosts that automatically append `$user` to `$tempdir`. As
# written, this will remove only the first `$user` in the path.
# Remove the extra `$user` node from a `$tempdir/$user` entry for
# hosts that automatically append `$user` to `$tempdir`.
if path.startswith(os.path.join('$tempdir', '$user')) and tmp_has_usr:
path = path.replace("/$user", "", 1)

paths.append(sup.canonicalize_path(path))
# Ensure the path is unique per user.
can_path = sup.canonicalize_path(path)
if user not in can_path:
can_path = os.path.join(can_path, user)

paths.append(can_path)

return paths

Expand All @@ -148,14 +158,6 @@ def get_stage_root():
raise StageError("No accessible stage paths in:",
' '.join(resolved_candidates))

# Ensure that path is unique per user in an attempt to avoid
# conflicts in shared temporary spaces. Emulate permissions from
# `tempfile.mkdtemp`.
user = getpass.getuser()
if user not in path:
path = os.path.join(path, user)
mkdirp(path, mode=stat.S_IRWXU)

_stage_root = path

return _stage_root
Expand Down
11 changes: 4 additions & 7 deletions lib/spack/spack/test/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,14 +627,13 @@ def test_add_command_line_scopes(tmpdir, mutable_config):
spack.config._add_command_line_scopes(mutable_config, [str(tmpdir)])


@pytest.mark.nomockstage
def test_nested_override():
"""Ensure proper scope naming of nested overrides."""
# WARNING: Base name must match that used in `config.py`s `override()`.
base_name = 'overrides-'
base_name = spack.config.overrides_base_name

def _check_scopes(num_expected, debug_values):
scope_names = [s.name for s in spack.config.config.scopes.values()]
scope_names = [s.name for s in spack.config.config.scopes.values() if
s.name.startswith(base_name)]

for i in range(num_expected):
name = '{0}{1}'.format(base_name, i)
Expand All @@ -651,11 +650,9 @@ def _check_scopes(num_expected, debug_values):
_check_scopes(1, [True])


@pytest.mark.nomockstage
def test_alternate_override(monkeypatch):
"""Ensure proper scope naming of override when conflict present."""
# WARNING: Base name must match that used in `config.py`s `override()`.
base_name = 'overrides-'
base_name = spack.config.overrides_base_name

def _matching_scopes(regexpr):
return [spack.config.InternalConfigScope('{0}1'.format(base_name))]
Expand Down
40 changes: 13 additions & 27 deletions lib/spack/spack/test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import pytest
import ruamel.yaml as yaml

from llnl.util.filesystem import remove_linked_tree
from llnl.util.filesystem import mkdirp, remove_linked_tree

import spack.architecture
import spack.compilers
Expand Down Expand Up @@ -131,41 +131,27 @@ def reset_compiler_cache():
spack.compilers._compiler_cache = {}


@pytest.fixture
def clear_stage_root(monkeypatch):
"""Ensure spack.stage._stage_root is not set at test start."""
monkeypatch.setattr(spack.stage, '_stage_root', None)


@pytest.fixture(scope='function', autouse=True)
def mock_stage(clear_stage_root, tmpdir_factory, request):
"""
Establish the temporary build_stage for the mock archive.
This fixture can be disabled for non-staging tests by adding::
@pytest.mark.nomockstage
Note 'check_for_leftover_stage_files' is the companion fixture for stage
directory checks and cleanup.
"""
def mock_stage(tmpdir_factory, monkeypatch, request):
"""Establish the temporary build_stage for the mock archive."""
# The approach with this autouse fixture is to set the stage root
# instead of using spack.config.override() to avoid configuration
# conflicts with dozens of tests that rely on other configuration
# fixtures, such as config.
if 'nomockstage' not in request.keywords:
# Set the build stage to the requested path
new_stage = tmpdir_factory.mktemp('mock-stage')
new_stage_path = str(new_stage)

# Set test_stage_path as the default directory to use for test stages.
current = spack.config.get('config:build_stage')
spack.config.set('config',
{'build_stage': new_stage_path}, scope='user')
# Ensure the source directory exists within the new stage path
source_path = os.path.join(new_stage_path,
spack.stage._source_path_subdir)
mkdirp(source_path)

# Ensure the source directory exists
source_path = new_stage.join(spack.stage._source_path_subdir)
source_path.ensure(dir=True)
monkeypatch.setattr(spack.stage, '_stage_root', new_stage_path)

yield new_stage_path

spack.config.set('config', {'build_stage': current}, scope='user')

# Clean up the test stage directory
if os.path.isdir(new_stage_path):
shutil.rmtree(new_stage_path)
Expand Down
Loading

0 comments on commit 92d1a1d

Please sign in to comment.