Move temp directory configuration to config.yaml
- Moved temp finding logic to spack.stage - Updated stage tests - Added tests for new path substaitution of $user, $spack, $tempdir
This commit is contained in:
parent
9347f86939
commit
0da639298c
@ -31,13 +31,13 @@ config:
|
|||||||
# You can use $tempdir to refer to the system default temp directory
|
# You can use $tempdir to refer to the system default temp directory
|
||||||
# (as returned by tempfile.gettempdir()).
|
# (as returned by tempfile.gettempdir()).
|
||||||
#
|
#
|
||||||
# A value of $local indicates that Spack should run builds directly
|
# A value of $spack/var/spack/stage indicates that Spack should run
|
||||||
# inside its install directory without staging them in temporary space.
|
# builds directly inside its install directory without staging them in
|
||||||
|
# temporary space.
|
||||||
build_stage:
|
build_stage:
|
||||||
- /usr/workspace/*/%u
|
|
||||||
- $tempdir
|
- $tempdir
|
||||||
- /nfs/tmp2/%u
|
- /nfs/tmp2/$user
|
||||||
- $local
|
- $spack/var/spack/stage
|
||||||
|
|
||||||
|
|
||||||
# Cache directory already downloaded source tarballs and archived
|
# Cache directory already downloaded source tarballs and archived
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
import collections
|
import collections
|
||||||
import errno
|
import errno
|
||||||
import fileinput
|
import fileinput
|
||||||
import getpass
|
|
||||||
import glob
|
import glob
|
||||||
import numbers
|
import numbers
|
||||||
import os
|
import os
|
||||||
@ -46,7 +45,6 @@
|
|||||||
'can_access',
|
'can_access',
|
||||||
'change_sed_delimiter',
|
'change_sed_delimiter',
|
||||||
'copy_mode',
|
'copy_mode',
|
||||||
'expand_user',
|
|
||||||
'filter_file',
|
'filter_file',
|
||||||
'find_libraries',
|
'find_libraries',
|
||||||
'fix_darwin_install_name',
|
'fix_darwin_install_name',
|
||||||
@ -229,16 +227,6 @@ def is_exe(path):
|
|||||||
return os.path.isfile(path) and os.access(path, os.X_OK)
|
return os.path.isfile(path) and os.access(path, os.X_OK)
|
||||||
|
|
||||||
|
|
||||||
def expand_user(path):
|
|
||||||
"""Find instances of '%u' in a path and replace with the current user's
|
|
||||||
username."""
|
|
||||||
username = getpass.getuser()
|
|
||||||
if not username and '%u' in path:
|
|
||||||
tty.die("Couldn't get username to complete path '%s'" % path)
|
|
||||||
|
|
||||||
return path.replace('%u', username)
|
|
||||||
|
|
||||||
|
|
||||||
def mkdirp(*paths):
|
def mkdirp(*paths):
|
||||||
"""Creates a directory, as well as parent directories if needed."""
|
"""Creates a directory, as well as parent directories if needed."""
|
||||||
for path in paths:
|
for path in paths:
|
||||||
|
@ -119,27 +119,6 @@
|
|||||||
# certifiates. e.g., curl should use the -k option.
|
# certifiates. e.g., curl should use the -k option.
|
||||||
insecure = False
|
insecure = False
|
||||||
|
|
||||||
# Whether to build in tmp space or directly in the stage_path.
|
|
||||||
# If this is true, then spack will make stage directories in
|
|
||||||
# a tmp filesystem, and it will symlink them into stage_path.
|
|
||||||
use_tmp_stage = True
|
|
||||||
|
|
||||||
# Locations to use for staging and building, in order of preference
|
|
||||||
# Use a %u to add a username to the stage paths here, in case this
|
|
||||||
# is a shared filesystem. Spack will use the first of these paths
|
|
||||||
# that it can create.
|
|
||||||
tmp_dirs = []
|
|
||||||
_default_tmp = tempfile.gettempdir()
|
|
||||||
_tmp_user = getpass.getuser()
|
|
||||||
|
|
||||||
_tmp_candidates = (_default_tmp, '/nfs/tmp2', '/tmp', '/var/tmp')
|
|
||||||
for path in _tmp_candidates:
|
|
||||||
# don't add a second username if it's already unique by user.
|
|
||||||
if _tmp_user not in path:
|
|
||||||
tmp_dirs.append(join_path(path, '%u', 'spack-stage'))
|
|
||||||
else:
|
|
||||||
tmp_dirs.append(join_path(path, 'spack-stage'))
|
|
||||||
|
|
||||||
# Whether spack should allow installation of unsafe versions of
|
# Whether spack should allow installation of unsafe versions of
|
||||||
# software. "Unsafe" versions are ones it doesn't have a checksum
|
# software. "Unsafe" versions are ones it doesn't have a checksum
|
||||||
# for.
|
# for.
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
import spack.error
|
import spack.error
|
||||||
import spack.spec
|
import spack.spec
|
||||||
from spack.provider_index import ProviderIndex
|
from spack.provider_index import ProviderIndex
|
||||||
|
from spack.util.path import canonicalize_path
|
||||||
from spack.util.naming import *
|
from spack.util.naming import *
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -93,19 +94,6 @@ def __getattr__(self, name):
|
|||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
|
|
||||||
|
|
||||||
def substitute_spack_prefix(path):
|
|
||||||
"""Replaces instances of $spack with Spack's prefix."""
|
|
||||||
return re.sub(r'^\$spack', spack.prefix, path)
|
|
||||||
|
|
||||||
|
|
||||||
def canonicalize_path(path):
|
|
||||||
"""Substitute $spack, expand user home, take abspath."""
|
|
||||||
path = substitute_spack_prefix(path)
|
|
||||||
path = os.path.expanduser(path)
|
|
||||||
path = os.path.abspath(path)
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
class RepoPath(object):
|
class RepoPath(object):
|
||||||
"""A RepoPath is a list of repos that function as one.
|
"""A RepoPath is a list of repos that function as one.
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import getpass
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
@ -41,9 +42,72 @@
|
|||||||
import spack.fetch_strategy as fs
|
import spack.fetch_strategy as fs
|
||||||
import spack.error
|
import spack.error
|
||||||
from spack.version import *
|
from spack.version import *
|
||||||
|
from spack.util.path import canonicalize_path
|
||||||
from spack.util.crypto import prefix_bits, bit_length
|
from spack.util.crypto import prefix_bits, bit_length
|
||||||
|
|
||||||
STAGE_PREFIX = 'spack-stage-'
|
_stage_prefix = 'spack-stage-'
|
||||||
|
|
||||||
|
|
||||||
|
def _first_accessible_path(paths):
|
||||||
|
"""Find a tmp dir that exists that we can access."""
|
||||||
|
for path in paths:
|
||||||
|
try:
|
||||||
|
# try to create the path if it doesn't exist.
|
||||||
|
path = canonicalize_path(path)
|
||||||
|
mkdirp(path)
|
||||||
|
|
||||||
|
# ensure accessible
|
||||||
|
if not can_access(path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# return it if successful.
|
||||||
|
return path
|
||||||
|
|
||||||
|
except OSError:
|
||||||
|
tty.debug('OSError while checking temporary path: %s' % path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# cached temporary root
|
||||||
|
_tmp_root = None
|
||||||
|
_use_tmp_stage = True
|
||||||
|
|
||||||
|
|
||||||
|
def get_tmp_root():
|
||||||
|
global _tmp_root, _use_tmp_stage
|
||||||
|
|
||||||
|
if not _use_tmp_stage:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if _tmp_root is None:
|
||||||
|
config = spack.config.get_config('config')
|
||||||
|
candidates = config['build_stage']
|
||||||
|
if isinstance(candidates, basestring):
|
||||||
|
candidates = [candidates]
|
||||||
|
|
||||||
|
path = _first_accessible_path(candidates)
|
||||||
|
if not path:
|
||||||
|
raise StageError("No accessible stage paths in %s", candidates)
|
||||||
|
|
||||||
|
# Return None to indicate we're using a local staging area.
|
||||||
|
if path == canonicalize_path(spack.stage_path):
|
||||||
|
_use_tmp_stage = False
|
||||||
|
return None
|
||||||
|
|
||||||
|
# ensure that any temp path is unique per user, so users don't
|
||||||
|
# fight over shared temporary space.
|
||||||
|
user = getpass.getuser()
|
||||||
|
if user not in path:
|
||||||
|
path = os.path.join(path, user, 'spack-stage')
|
||||||
|
else:
|
||||||
|
path = os.path.join(path, 'spack-stage')
|
||||||
|
|
||||||
|
mkdirp(path)
|
||||||
|
_tmp_root = path
|
||||||
|
|
||||||
|
return _tmp_root
|
||||||
|
|
||||||
|
|
||||||
class Stage(object):
|
class Stage(object):
|
||||||
@ -141,9 +205,8 @@ def __init__(
|
|||||||
# TODO : won't be the same as the temporary stage area in tmp_root
|
# TODO : won't be the same as the temporary stage area in tmp_root
|
||||||
self.name = name
|
self.name = name
|
||||||
if name is None:
|
if name is None:
|
||||||
self.name = STAGE_PREFIX + next(tempfile._get_candidate_names())
|
self.name = _stage_prefix + next(tempfile._get_candidate_names())
|
||||||
self.mirror_path = mirror_path
|
self.mirror_path = mirror_path
|
||||||
self.tmp_root = find_tmp_root()
|
|
||||||
|
|
||||||
# Try to construct here a temporary name for the stage directory
|
# Try to construct here a temporary name for the stage directory
|
||||||
# If this is a named stage, then construct a named path.
|
# If this is a named stage, then construct a named path.
|
||||||
@ -217,10 +280,11 @@ def _need_to_create_path(self):
|
|||||||
|
|
||||||
# Path looks ok, but need to check the target of the link.
|
# Path looks ok, but need to check the target of the link.
|
||||||
if os.path.islink(self.path):
|
if os.path.islink(self.path):
|
||||||
real_path = os.path.realpath(self.path)
|
tmp_root = get_tmp_root()
|
||||||
real_tmp = os.path.realpath(self.tmp_root)
|
if tmp_root is not None:
|
||||||
|
real_path = os.path.realpath(self.path)
|
||||||
|
real_tmp = os.path.realpath(tmp_root)
|
||||||
|
|
||||||
if spack.use_tmp_stage:
|
|
||||||
# If we're using a tmp dir, it's a link, and it points at the
|
# If we're using a tmp dir, it's a link, and it points at the
|
||||||
# right spot, then keep it.
|
# right spot, then keep it.
|
||||||
if (real_path.startswith(real_tmp) and
|
if (real_path.startswith(real_tmp) and
|
||||||
@ -416,11 +480,11 @@ def chdir_to_source(self):
|
|||||||
"""
|
"""
|
||||||
path = self.source_path
|
path = self.source_path
|
||||||
if not path:
|
if not path:
|
||||||
tty.die("Attempt to chdir before expanding archive.")
|
raise StageError("Attempt to chdir before expanding archive.")
|
||||||
else:
|
else:
|
||||||
os.chdir(path)
|
os.chdir(path)
|
||||||
if not os.listdir(path):
|
if not os.listdir(path):
|
||||||
tty.die("Archive was empty for %s" % self.name)
|
raise StageError("Archive was empty for %s" % self.name)
|
||||||
|
|
||||||
def restage(self):
|
def restage(self):
|
||||||
"""Removes the expanded archive path if it exists, then re-expands
|
"""Removes the expanded archive path if it exists, then re-expands
|
||||||
@ -429,17 +493,17 @@ def restage(self):
|
|||||||
self.fetcher.reset()
|
self.fetcher.reset()
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
"""
|
"""Creates the stage directory.
|
||||||
Creates the stage directory
|
|
||||||
|
|
||||||
If self.tmp_root evaluates to False, the stage directory is
|
If get_tmp_root() is None, the stage directory is created
|
||||||
created directly under spack.stage_path, otherwise this will
|
directly under spack.stage_path, otherwise this will attempt to
|
||||||
attempt to create a stage in a temporary directory and link it
|
create a stage in a temporary directory and link it into
|
||||||
into spack.stage_path.
|
spack.stage_path.
|
||||||
|
|
||||||
Spack will use the first writable location in spack.tmp_dirs
|
Spack will use the first writable location in spack.tmp_dirs
|
||||||
to create a stage. If there is no valid location in tmp_dirs,
|
to create a stage. If there is no valid location in tmp_dirs,
|
||||||
fall back to making the stage inside spack.stage_path.
|
fall back to making the stage inside spack.stage_path.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Create the top-level stage directory
|
# Create the top-level stage directory
|
||||||
mkdirp(spack.stage_path)
|
mkdirp(spack.stage_path)
|
||||||
@ -448,8 +512,10 @@ def create(self):
|
|||||||
# If a tmp_root exists then create a directory there and then link it
|
# If a tmp_root exists then create a directory there and then link it
|
||||||
# in the stage area, otherwise create the stage directory in self.path
|
# in the stage area, otherwise create the stage directory in self.path
|
||||||
if self._need_to_create_path():
|
if self._need_to_create_path():
|
||||||
if self.tmp_root:
|
tmp_root = get_tmp_root()
|
||||||
tmp_dir = tempfile.mkdtemp('', STAGE_PREFIX, self.tmp_root)
|
if tmp_root is not None:
|
||||||
|
tmp_dir = tempfile.mkdtemp('', _stage_prefix, tmp_root)
|
||||||
|
tty.debug('link %s -> %s' % (self.path, tmp_dir))
|
||||||
os.symlink(tmp_dir, self.path)
|
os.symlink(tmp_dir, self.path)
|
||||||
else:
|
else:
|
||||||
mkdirp(self.path)
|
mkdirp(self.path)
|
||||||
@ -614,25 +680,6 @@ def purge():
|
|||||||
remove_linked_tree(stage_path)
|
remove_linked_tree(stage_path)
|
||||||
|
|
||||||
|
|
||||||
def find_tmp_root():
|
|
||||||
if spack.use_tmp_stage:
|
|
||||||
for tmp in spack.tmp_dirs:
|
|
||||||
try:
|
|
||||||
# Replace %u with username
|
|
||||||
expanded = expand_user(tmp)
|
|
||||||
|
|
||||||
# try to create a directory for spack stuff
|
|
||||||
mkdirp(expanded)
|
|
||||||
|
|
||||||
# return it if successful.
|
|
||||||
return expanded
|
|
||||||
|
|
||||||
except OSError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class StageError(spack.error.SpackError):
|
class StageError(spack.error.SpackError):
|
||||||
""""Superclass for all errors encountered during staging."""
|
""""Superclass for all errors encountered during staging."""
|
||||||
|
|
||||||
|
@ -24,10 +24,12 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import getpass
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.config
|
import spack.config
|
||||||
|
from spack.util.path import canonicalize_path
|
||||||
from ordereddict_backport import OrderedDict
|
from ordereddict_backport import OrderedDict
|
||||||
from spack.test.mock_packages_test import *
|
from spack.test.mock_packages_test import *
|
||||||
|
|
||||||
@ -217,3 +219,53 @@ def test_write_to_same_priority_file(self):
|
|||||||
# Same check again, to ensure consistency.
|
# Same check again, to ensure consistency.
|
||||||
self.check_config(a_comps, *self.a_comp_specs)
|
self.check_config(a_comps, *self.a_comp_specs)
|
||||||
self.check_config(b_comps, *self.b_comp_specs)
|
self.check_config(b_comps, *self.b_comp_specs)
|
||||||
|
|
||||||
|
def check_canonical(self, var, expected):
|
||||||
|
"""ensure things are substituted properly and canonicalized."""
|
||||||
|
path = '/foo/bar/baz'
|
||||||
|
|
||||||
|
self.assertEqual(canonicalize_path(var + path),
|
||||||
|
expected + path)
|
||||||
|
|
||||||
|
self.assertEqual(canonicalize_path(path + var),
|
||||||
|
path + '/' + expected)
|
||||||
|
|
||||||
|
self.assertEqual(canonicalize_path(path + var + path),
|
||||||
|
expected + path)
|
||||||
|
|
||||||
|
def test_substitute_config_variables(self):
|
||||||
|
prefix = spack.prefix.lstrip('/')
|
||||||
|
|
||||||
|
self.assertEqual(os.path.join('/foo/bar/baz', prefix),
|
||||||
|
canonicalize_path('/foo/bar/baz/$spack'))
|
||||||
|
|
||||||
|
self.assertEqual(os.path.join(spack.prefix, 'foo/bar/baz'),
|
||||||
|
canonicalize_path('$spack/foo/bar/baz/'))
|
||||||
|
|
||||||
|
self.assertEqual(os.path.join('/foo/bar/baz', prefix, 'foo/bar/baz'),
|
||||||
|
canonicalize_path('/foo/bar/baz/$spack/foo/bar/baz/'))
|
||||||
|
|
||||||
|
self.assertEqual(os.path.join('/foo/bar/baz', prefix),
|
||||||
|
canonicalize_path('/foo/bar/baz/${spack}'))
|
||||||
|
|
||||||
|
self.assertEqual(os.path.join(spack.prefix, 'foo/bar/baz'),
|
||||||
|
canonicalize_path('${spack}/foo/bar/baz/'))
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
os.path.join('/foo/bar/baz', prefix, 'foo/bar/baz'),
|
||||||
|
canonicalize_path('/foo/bar/baz/${spack}/foo/bar/baz/'))
|
||||||
|
|
||||||
|
self.assertNotEqual(
|
||||||
|
os.path.join('/foo/bar/baz', prefix, 'foo/bar/baz'),
|
||||||
|
canonicalize_path('/foo/bar/baz/${spack/foo/bar/baz/'))
|
||||||
|
|
||||||
|
def test_substitute_user(self):
|
||||||
|
user = getpass.getuser()
|
||||||
|
self.assertEqual('/foo/bar/' + user + '/baz',
|
||||||
|
canonicalize_path('/foo/bar/$user/baz'))
|
||||||
|
|
||||||
|
def test_substitute_tempdir(self):
|
||||||
|
tempdir = tempfile.gettempdir()
|
||||||
|
self.assertEqual(tempdir, canonicalize_path('$tempdir'))
|
||||||
|
self.assertEqual(tempdir + '/foo/bar/baz',
|
||||||
|
canonicalize_path('$tempdir/foo/bar/baz'))
|
||||||
|
@ -180,6 +180,27 @@
|
|||||||
externalmodule@1.0%gcc@4.5.0: external-module
|
externalmodule@1.0%gcc@4.5.0: external-module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
mock_config = """\
|
||||||
|
config:
|
||||||
|
install_tree: $spack/opt/spack
|
||||||
|
build_stage:
|
||||||
|
- $tempdir
|
||||||
|
- /nfs/tmp2/$user
|
||||||
|
- $spack/var/spack/stage
|
||||||
|
source_cache: $spack/var/spack/cache
|
||||||
|
misc_cache: ~/.spack/cache
|
||||||
|
verify_ssl: true
|
||||||
|
checksum: true
|
||||||
|
dirty: false
|
||||||
|
"""
|
||||||
|
|
||||||
|
# these are written out to mock config files.
|
||||||
|
mock_configs = {
|
||||||
|
'config.yaml': mock_config,
|
||||||
|
'compilers.yaml': mock_compiler_config,
|
||||||
|
'packages.yaml': mock_packages_config,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class MockPackagesTest(unittest.TestCase):
|
class MockPackagesTest(unittest.TestCase):
|
||||||
|
|
||||||
@ -199,11 +220,10 @@ def initmock(self):
|
|||||||
self.mock_user_config = os.path.join(self.temp_config, 'user')
|
self.mock_user_config = os.path.join(self.temp_config, 'user')
|
||||||
mkdirp(self.mock_site_config)
|
mkdirp(self.mock_site_config)
|
||||||
mkdirp(self.mock_user_config)
|
mkdirp(self.mock_user_config)
|
||||||
for confs in [('compilers.yaml', mock_compiler_config),
|
for filename, data in mock_configs.items():
|
||||||
('packages.yaml', mock_packages_config)]:
|
conf_yaml = os.path.join(self.mock_site_config, filename)
|
||||||
conf_yaml = os.path.join(self.mock_site_config, confs[0])
|
|
||||||
with open(conf_yaml, 'w') as f:
|
with open(conf_yaml, 'w') as f:
|
||||||
f.write(confs[1])
|
f.write(data)
|
||||||
|
|
||||||
# TODO: Mocking this up is kind of brittle b/c ConfigScope
|
# TODO: Mocking this up is kind of brittle b/c ConfigScope
|
||||||
# TODO: constructor modifies config_scopes. Make it cleaner.
|
# TODO: constructor modifies config_scopes. Make it cleaner.
|
||||||
|
@ -27,64 +27,71 @@
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import unittest
|
import tempfile
|
||||||
from contextlib import *
|
from contextlib import *
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
|
import spack.stage
|
||||||
from llnl.util.filesystem import *
|
from llnl.util.filesystem import *
|
||||||
from spack.stage import Stage
|
from spack.stage import Stage
|
||||||
from spack.util.executable import which
|
from spack.util.executable import which
|
||||||
|
from spack.test.mock_packages_test import *
|
||||||
|
|
||||||
test_files_dir = os.path.realpath(join_path(spack.stage_path, '.test'))
|
_test_tmp_path = None
|
||||||
test_tmp_path = os.path.realpath(join_path(test_files_dir, 'tmp'))
|
|
||||||
|
|
||||||
archive_dir = 'test-files'
|
|
||||||
archive_name = archive_dir + '.tar.gz'
|
|
||||||
archive_dir_path = join_path(test_files_dir, archive_dir)
|
|
||||||
archive_url = 'file://' + join_path(test_files_dir, archive_name)
|
|
||||||
readme_name = 'README.txt'
|
|
||||||
test_readme = join_path(archive_dir_path, readme_name)
|
|
||||||
readme_text = "hello world!\n"
|
|
||||||
|
|
||||||
stage_name = 'spack-test-stage'
|
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def use_tmp(use_tmp):
|
def use_tmp(use_tmp):
|
||||||
"""Allow some test code to be executed with spack.use_tmp_stage
|
"""Allow some test code to be executed such that spack will either use or
|
||||||
set to a certain value. Context manager makes sure it's reset
|
not use temporary space for stages.
|
||||||
on failure.
|
|
||||||
"""
|
"""
|
||||||
old_tmp = spack.use_tmp_stage
|
# mock up config
|
||||||
spack.use_tmp_stage = use_tmp
|
path = _test_tmp_path if use_tmp else spack.stage_path
|
||||||
|
spack.config.update_config(
|
||||||
|
'config', {'build_stage': [path]}, scope='user')
|
||||||
yield
|
yield
|
||||||
spack.use_tmp_stage = old_tmp
|
|
||||||
|
|
||||||
|
|
||||||
class StageTest(unittest.TestCase):
|
class StageTest(MockPackagesTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""This sets up a mock archive to fetch, and a mock temp space for use
|
"""This sets up a mock archive to fetch, and a mock temp space for use
|
||||||
by the Stage class. It doesn't actually create the Stage -- that
|
by the Stage class. It doesn't actually create the Stage -- that
|
||||||
is done by individual tests.
|
is done by individual tests.
|
||||||
"""
|
"""
|
||||||
if os.path.exists(test_files_dir):
|
global _test_tmp_path
|
||||||
shutil.rmtree(test_files_dir)
|
|
||||||
|
self.test_files_dir = tempfile.mkdtemp()
|
||||||
|
self.test_tmp_path = os.path.realpath(
|
||||||
|
os.path.join(self.test_files_dir, 'tmp'))
|
||||||
|
_test_tmp_path = self.test_tmp_path
|
||||||
|
|
||||||
|
self.archive_dir = 'test-files'
|
||||||
|
self.archive_name = self.archive_dir + '.tar.gz'
|
||||||
|
archive_dir_path = os.path.join(self.test_files_dir,
|
||||||
|
self.archive_dir)
|
||||||
|
self.archive_url = 'file://' + os.path.join(self.test_files_dir,
|
||||||
|
self.archive_name)
|
||||||
|
test_readme = join_path(archive_dir_path, 'README.txt')
|
||||||
|
self.readme_text = "hello world!\n"
|
||||||
|
|
||||||
|
self.stage_name = 'spack-test-stage'
|
||||||
|
|
||||||
mkdirp(test_files_dir)
|
|
||||||
mkdirp(archive_dir_path)
|
mkdirp(archive_dir_path)
|
||||||
mkdirp(test_tmp_path)
|
mkdirp(self.test_tmp_path)
|
||||||
|
|
||||||
with open(test_readme, 'w') as readme:
|
with open(test_readme, 'w') as readme:
|
||||||
readme.write(readme_text)
|
readme.write(self.readme_text)
|
||||||
|
|
||||||
with working_dir(test_files_dir):
|
with working_dir(self.test_files_dir):
|
||||||
tar = which('tar')
|
tar = which('tar', required=True)
|
||||||
tar('czf', archive_name, archive_dir)
|
tar('czf', self.archive_name, self.archive_dir)
|
||||||
|
|
||||||
# Make spack use the test environment for tmp stuff.
|
# Make spack use the test environment for tmp stuff.
|
||||||
self.old_tmp_dirs = spack.tmp_dirs
|
self._old_tmp_root = spack.stage._tmp_root
|
||||||
spack.tmp_dirs = [test_tmp_path]
|
self._old_use_tmp_stage = spack.stage._use_tmp_stage
|
||||||
|
spack.stage._tmp_root = None
|
||||||
|
spack.stage._use_tmp_stage = True
|
||||||
|
|
||||||
# record this since this test changes to directories that will
|
# record this since this test changes to directories that will
|
||||||
# be removed.
|
# be removed.
|
||||||
@ -92,13 +99,14 @@ def setUp(self):
|
|||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Blows away the test environment directory."""
|
"""Blows away the test environment directory."""
|
||||||
shutil.rmtree(test_files_dir)
|
shutil.rmtree(self.test_files_dir, ignore_errors=True)
|
||||||
|
|
||||||
# chdir back to original working dir
|
# chdir back to original working dir
|
||||||
os.chdir(self.working_dir)
|
os.chdir(self.working_dir)
|
||||||
|
|
||||||
# restore spack's original tmp environment
|
# restore spack's original tmp environment
|
||||||
spack.tmp_dirs = self.old_tmp_dirs
|
spack.stage._tmp_root = self._old_tmp_root
|
||||||
|
spack.stage._use_tmp_stage = self._old_use_tmp_stage
|
||||||
|
|
||||||
def get_stage_path(self, stage, stage_name):
|
def get_stage_path(self, stage, stage_name):
|
||||||
"""Figure out where a stage should be living. This depends on
|
"""Figure out where a stage should be living. This depends on
|
||||||
@ -120,7 +128,7 @@ def check_setup(self, stage, stage_name):
|
|||||||
# Ensure stage was created in the spack stage directory
|
# Ensure stage was created in the spack stage directory
|
||||||
self.assertTrue(os.path.isdir(stage_path))
|
self.assertTrue(os.path.isdir(stage_path))
|
||||||
|
|
||||||
if spack.use_tmp_stage:
|
if spack.stage.get_tmp_root():
|
||||||
# Check that the stage dir is really a symlink.
|
# Check that the stage dir is really a symlink.
|
||||||
self.assertTrue(os.path.islink(stage_path))
|
self.assertTrue(os.path.islink(stage_path))
|
||||||
|
|
||||||
@ -131,7 +139,7 @@ def check_setup(self, stage, stage_name):
|
|||||||
|
|
||||||
# Make sure the directory is in the place we asked it to
|
# Make sure the directory is in the place we asked it to
|
||||||
# be (see setUp and tearDown)
|
# be (see setUp and tearDown)
|
||||||
self.assertTrue(target.startswith(test_tmp_path))
|
self.assertTrue(target.startswith(self.test_tmp_path))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Make sure the stage path is NOT a link for a non-tmp stage
|
# Make sure the stage path is NOT a link for a non-tmp stage
|
||||||
@ -139,24 +147,24 @@ def check_setup(self, stage, stage_name):
|
|||||||
|
|
||||||
def check_fetch(self, stage, stage_name):
|
def check_fetch(self, stage, stage_name):
|
||||||
stage_path = self.get_stage_path(stage, stage_name)
|
stage_path = self.get_stage_path(stage, stage_name)
|
||||||
self.assertTrue(archive_name in os.listdir(stage_path))
|
self.assertTrue(self.archive_name in os.listdir(stage_path))
|
||||||
self.assertEqual(join_path(stage_path, archive_name),
|
self.assertEqual(join_path(stage_path, self.archive_name),
|
||||||
stage.fetcher.archive_file)
|
stage.fetcher.archive_file)
|
||||||
|
|
||||||
def check_expand_archive(self, stage, stage_name):
|
def check_expand_archive(self, stage, stage_name):
|
||||||
stage_path = self.get_stage_path(stage, stage_name)
|
stage_path = self.get_stage_path(stage, stage_name)
|
||||||
self.assertTrue(archive_name in os.listdir(stage_path))
|
self.assertTrue(self.archive_name in os.listdir(stage_path))
|
||||||
self.assertTrue(archive_dir in os.listdir(stage_path))
|
self.assertTrue(self.archive_dir in os.listdir(stage_path))
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
join_path(stage_path, archive_dir),
|
join_path(stage_path, self.archive_dir),
|
||||||
stage.source_path)
|
stage.source_path)
|
||||||
|
|
||||||
readme = join_path(stage_path, archive_dir, readme_name)
|
readme = join_path(stage_path, self.archive_dir, 'README.txt')
|
||||||
self.assertTrue(os.path.isfile(readme))
|
self.assertTrue(os.path.isfile(readme))
|
||||||
|
|
||||||
with open(readme) as file:
|
with open(readme) as file:
|
||||||
self.assertEqual(readme_text, file.read())
|
self.assertEqual(self.readme_text, file.read())
|
||||||
|
|
||||||
def check_chdir(self, stage, stage_name):
|
def check_chdir(self, stage, stage_name):
|
||||||
stage_path = self.get_stage_path(stage, stage_name)
|
stage_path = self.get_stage_path(stage, stage_name)
|
||||||
@ -165,7 +173,7 @@ def check_chdir(self, stage, stage_name):
|
|||||||
def check_chdir_to_source(self, stage, stage_name):
|
def check_chdir_to_source(self, stage, stage_name):
|
||||||
stage_path = self.get_stage_path(stage, stage_name)
|
stage_path = self.get_stage_path(stage, stage_name)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
join_path(os.path.realpath(stage_path), archive_dir),
|
join_path(os.path.realpath(stage_path), self.archive_dir),
|
||||||
os.getcwd())
|
os.getcwd())
|
||||||
|
|
||||||
def check_destroy(self, stage, stage_name):
|
def check_destroy(self, stage, stage_name):
|
||||||
@ -176,76 +184,76 @@ def check_destroy(self, stage, stage_name):
|
|||||||
self.assertFalse(os.path.exists(stage_path))
|
self.assertFalse(os.path.exists(stage_path))
|
||||||
|
|
||||||
# tmp stage needs to remove tmp dir too.
|
# tmp stage needs to remove tmp dir too.
|
||||||
if spack.use_tmp_stage:
|
if spack.stage._use_tmp_stage:
|
||||||
target = os.path.realpath(stage_path)
|
target = os.path.realpath(stage_path)
|
||||||
self.assertFalse(os.path.exists(target))
|
self.assertFalse(os.path.exists(target))
|
||||||
|
|
||||||
def test_setup_and_destroy_name_with_tmp(self):
|
def test_setup_and_destroy_name_with_tmp(self):
|
||||||
with use_tmp(True):
|
with use_tmp(True):
|
||||||
with Stage(archive_url, name=stage_name) as stage:
|
with Stage(self.archive_url, name=self.stage_name) as stage:
|
||||||
self.check_setup(stage, stage_name)
|
self.check_setup(stage, self.stage_name)
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_setup_and_destroy_name_without_tmp(self):
|
def test_setup_and_destroy_name_without_tmp(self):
|
||||||
with use_tmp(False):
|
with use_tmp(False):
|
||||||
with Stage(archive_url, name=stage_name) as stage:
|
with Stage(self.archive_url, name=self.stage_name) as stage:
|
||||||
self.check_setup(stage, stage_name)
|
self.check_setup(stage, self.stage_name)
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_setup_and_destroy_no_name_with_tmp(self):
|
def test_setup_and_destroy_no_name_with_tmp(self):
|
||||||
with use_tmp(True):
|
with use_tmp(True):
|
||||||
with Stage(archive_url) as stage:
|
with Stage(self.archive_url) as stage:
|
||||||
self.check_setup(stage, None)
|
self.check_setup(stage, None)
|
||||||
self.check_destroy(stage, None)
|
self.check_destroy(stage, None)
|
||||||
|
|
||||||
def test_setup_and_destroy_no_name_without_tmp(self):
|
def test_setup_and_destroy_no_name_without_tmp(self):
|
||||||
with use_tmp(False):
|
with use_tmp(False):
|
||||||
with Stage(archive_url) as stage:
|
with Stage(self.archive_url) as stage:
|
||||||
self.check_setup(stage, None)
|
self.check_setup(stage, None)
|
||||||
self.check_destroy(stage, None)
|
self.check_destroy(stage, None)
|
||||||
|
|
||||||
def test_chdir(self):
|
def test_chdir(self):
|
||||||
with Stage(archive_url, name=stage_name) as stage:
|
with Stage(self.archive_url, name=self.stage_name) as stage:
|
||||||
stage.chdir()
|
stage.chdir()
|
||||||
self.check_setup(stage, stage_name)
|
self.check_setup(stage, self.stage_name)
|
||||||
self.check_chdir(stage, stage_name)
|
self.check_chdir(stage, self.stage_name)
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_fetch(self):
|
def test_fetch(self):
|
||||||
with Stage(archive_url, name=stage_name) as stage:
|
with Stage(self.archive_url, name=self.stage_name) as stage:
|
||||||
stage.fetch()
|
stage.fetch()
|
||||||
self.check_setup(stage, stage_name)
|
self.check_setup(stage, self.stage_name)
|
||||||
self.check_chdir(stage, stage_name)
|
self.check_chdir(stage, self.stage_name)
|
||||||
self.check_fetch(stage, stage_name)
|
self.check_fetch(stage, self.stage_name)
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_expand_archive(self):
|
def test_expand_archive(self):
|
||||||
with Stage(archive_url, name=stage_name) as stage:
|
with Stage(self.archive_url, name=self.stage_name) as stage:
|
||||||
stage.fetch()
|
stage.fetch()
|
||||||
self.check_setup(stage, stage_name)
|
self.check_setup(stage, self.stage_name)
|
||||||
self.check_fetch(stage, stage_name)
|
self.check_fetch(stage, self.stage_name)
|
||||||
stage.expand_archive()
|
stage.expand_archive()
|
||||||
self.check_expand_archive(stage, stage_name)
|
self.check_expand_archive(stage, self.stage_name)
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_expand_archive_with_chdir(self):
|
def test_expand_archive_with_chdir(self):
|
||||||
with Stage(archive_url, name=stage_name) as stage:
|
with Stage(self.archive_url, name=self.stage_name) as stage:
|
||||||
stage.fetch()
|
stage.fetch()
|
||||||
self.check_setup(stage, stage_name)
|
self.check_setup(stage, self.stage_name)
|
||||||
self.check_fetch(stage, stage_name)
|
self.check_fetch(stage, self.stage_name)
|
||||||
stage.expand_archive()
|
stage.expand_archive()
|
||||||
stage.chdir_to_source()
|
stage.chdir_to_source()
|
||||||
self.check_expand_archive(stage, stage_name)
|
self.check_expand_archive(stage, self.stage_name)
|
||||||
self.check_chdir_to_source(stage, stage_name)
|
self.check_chdir_to_source(stage, self.stage_name)
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_restage(self):
|
def test_restage(self):
|
||||||
with Stage(archive_url, name=stage_name) as stage:
|
with Stage(self.archive_url, name=self.stage_name) as stage:
|
||||||
stage.fetch()
|
stage.fetch()
|
||||||
stage.expand_archive()
|
stage.expand_archive()
|
||||||
stage.chdir_to_source()
|
stage.chdir_to_source()
|
||||||
self.check_expand_archive(stage, stage_name)
|
self.check_expand_archive(stage, self.stage_name)
|
||||||
self.check_chdir_to_source(stage, stage_name)
|
self.check_chdir_to_source(stage, self.stage_name)
|
||||||
|
|
||||||
# Try to make a file in the old archive dir
|
# Try to make a file in the old archive dir
|
||||||
with open('foobar', 'w') as file:
|
with open('foobar', 'w') as file:
|
||||||
@ -255,40 +263,44 @@ def test_restage(self):
|
|||||||
|
|
||||||
# Make sure the file is not there after restage.
|
# Make sure the file is not there after restage.
|
||||||
stage.restage()
|
stage.restage()
|
||||||
self.check_chdir(stage, stage_name)
|
self.check_chdir(stage, self.stage_name)
|
||||||
self.check_fetch(stage, stage_name)
|
self.check_fetch(stage, self.stage_name)
|
||||||
stage.chdir_to_source()
|
stage.chdir_to_source()
|
||||||
self.check_chdir_to_source(stage, stage_name)
|
self.check_chdir_to_source(stage, self.stage_name)
|
||||||
self.assertFalse('foobar' in os.listdir(stage.source_path))
|
self.assertFalse('foobar' in os.listdir(stage.source_path))
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_no_keep_without_exceptions(self):
|
def test_no_keep_without_exceptions(self):
|
||||||
with Stage(archive_url, name=stage_name, keep=False) as stage:
|
with Stage(self.archive_url,
|
||||||
|
name=self.stage_name, keep=False) as stage:
|
||||||
pass
|
pass
|
||||||
self.check_destroy(stage, stage_name)
|
self.check_destroy(stage, self.stage_name)
|
||||||
|
|
||||||
def test_keep_without_exceptions(self):
|
def test_keep_without_exceptions(self):
|
||||||
with Stage(archive_url, name=stage_name, keep=True) as stage:
|
with Stage(self.archive_url,
|
||||||
|
name=self.stage_name, keep=True) as stage:
|
||||||
pass
|
pass
|
||||||
path = self.get_stage_path(stage, stage_name)
|
path = self.get_stage_path(stage, self.stage_name)
|
||||||
self.assertTrue(os.path.isdir(path))
|
self.assertTrue(os.path.isdir(path))
|
||||||
|
|
||||||
def test_no_keep_with_exceptions(self):
|
def test_no_keep_with_exceptions(self):
|
||||||
try:
|
try:
|
||||||
with Stage(archive_url, name=stage_name, keep=False) as stage:
|
with Stage(self.archive_url,
|
||||||
|
name=self.stage_name, keep=False) as stage:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
path = self.get_stage_path(stage, stage_name)
|
path = self.get_stage_path(stage, self.stage_name)
|
||||||
self.assertTrue(os.path.isdir(path))
|
self.assertTrue(os.path.isdir(path))
|
||||||
except:
|
except:
|
||||||
pass # ignore here.
|
pass # ignore here.
|
||||||
|
|
||||||
def test_keep_exceptions(self):
|
def test_keep_exceptions(self):
|
||||||
try:
|
try:
|
||||||
with Stage(archive_url, name=stage_name, keep=True) as stage:
|
with Stage(self.archive_url,
|
||||||
|
name=self.stage_name, keep=True) as stage:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
path = self.get_stage_path(stage, stage_name)
|
path = self.get_stage_path(stage, self.stage_name)
|
||||||
self.assertTrue(os.path.isdir(path))
|
self.assertTrue(os.path.isdir(path))
|
||||||
except:
|
except:
|
||||||
pass # ignore here.
|
pass # ignore here.
|
||||||
|
68
lib/spack/spack/util/path.py
Normal file
68
lib/spack/spack/util/path.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at the Lawrence Livermore National Laboratory.
|
||||||
|
#
|
||||||
|
# This file is part of Spack.
|
||||||
|
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||||
|
# LLNL-CODE-647188
|
||||||
|
#
|
||||||
|
# For details, see https://github.com/llnl/spack
|
||||||
|
# Please also see the LICENSE file for our notice and the LGPL.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License (as
|
||||||
|
# published by the Free Software Foundation) version 2.1, February 1999.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
||||||
|
# conditions of the GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
##############################################################################
|
||||||
|
"""Utilities for managing paths in Spack.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import spack
|
||||||
|
import getpass
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'substitute_config_variables',
|
||||||
|
'canonicalize_path']
|
||||||
|
|
||||||
|
# Substitutions to perform
|
||||||
|
replacements = {
|
||||||
|
'spack': spack.prefix,
|
||||||
|
'user': getpass.getuser(),
|
||||||
|
'tempdir': tempfile.gettempdir(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def substitute_config_variables(path):
|
||||||
|
"""Substitute placeholders into paths.
|
||||||
|
|
||||||
|
Spack allows paths in configs to have some placeholders, as follows:
|
||||||
|
|
||||||
|
- $spack The Spack instance's prefix
|
||||||
|
- $user The current user's username
|
||||||
|
- $tempdir Default temporary directory returned by tempfile.gettempdir()
|
||||||
|
"""
|
||||||
|
# Look up replacements for re.sub in the replacements dict.
|
||||||
|
def repl(match):
|
||||||
|
m = match.group(0).strip('${}')
|
||||||
|
return replacements.get(m, match.group(0))
|
||||||
|
|
||||||
|
# Replace $var or ${var}.
|
||||||
|
return re.sub(r'(\$\w+\b|\$\{\w+\})', repl, path)
|
||||||
|
|
||||||
|
|
||||||
|
def canonicalize_path(path):
|
||||||
|
"""Substitute $spack, expand user home, take abspath."""
|
||||||
|
path = substitute_config_variables(path)
|
||||||
|
path = os.path.expanduser(path)
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
return path
|
Loading…
Reference in New Issue
Block a user