Compare commits
2 Commits
features/p
...
features/k
Author | SHA1 | Date | |
---|---|---|---|
![]() |
702774edea | ||
![]() |
7713dd4063 |
@@ -453,15 +453,19 @@ def _eval_conditional(string):
|
|||||||
return eval(string, valid_variables)
|
return eval(string, valid_variables)
|
||||||
|
|
||||||
|
|
||||||
|
_default_keep = 5
|
||||||
|
|
||||||
|
|
||||||
class ViewDescriptor(object):
|
class ViewDescriptor(object):
|
||||||
def __init__(self, base_path, root, projections={}, select=[], exclude=[],
|
def __init__(self, base_path, root, projections={}, select=[], exclude=[],
|
||||||
link=default_view_link):
|
link=default_view_link, keep=_default_keep):
|
||||||
self.base = base_path
|
self.base = base_path
|
||||||
self.root = spack.util.path.canonicalize_path(root)
|
self.root = spack.util.path.canonicalize_path(root)
|
||||||
self.projections = projections
|
self.projections = projections
|
||||||
self.select = select
|
self.select = select
|
||||||
self.exclude = exclude
|
self.exclude = exclude
|
||||||
self.link = link
|
self.link = link
|
||||||
|
self.keep = keep
|
||||||
|
|
||||||
def select_fn(self, spec):
|
def select_fn(self, spec):
|
||||||
return any(spec.satisfies(s) for s in self.select)
|
return any(spec.satisfies(s) for s in self.select)
|
||||||
@@ -474,7 +478,8 @@ def __eq__(self, other):
|
|||||||
self.projections == other.projections,
|
self.projections == other.projections,
|
||||||
self.select == other.select,
|
self.select == other.select,
|
||||||
self.exclude == other.exclude,
|
self.exclude == other.exclude,
|
||||||
self.link == other.link])
|
self.link == other.link,
|
||||||
|
self.keep == other.keep])
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
ret = syaml.syaml_dict([('root', self.root)])
|
ret = syaml.syaml_dict([('root', self.root)])
|
||||||
@@ -491,6 +496,8 @@ def to_dict(self):
|
|||||||
ret['exclude'] = self.exclude
|
ret['exclude'] = self.exclude
|
||||||
if self.link != default_view_link:
|
if self.link != default_view_link:
|
||||||
ret['link'] = self.link
|
ret['link'] = self.link
|
||||||
|
if self.keep != _default_keep:
|
||||||
|
ret['keep'] = self.keep
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -500,7 +507,13 @@ def from_dict(base_path, d):
|
|||||||
d.get('projections', {}),
|
d.get('projections', {}),
|
||||||
d.get('select', []),
|
d.get('select', []),
|
||||||
d.get('exclude', []),
|
d.get('exclude', []),
|
||||||
d.get('link', default_view_link))
|
d.get('link', default_view_link),
|
||||||
|
d.get('keep', _default_keep))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _impl_dir(self):
|
||||||
|
root_dir, root_name = os.path.split(self.root)
|
||||||
|
return os.path.join(root_dir, '._%s' % root_name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _current_root(self):
|
def _current_root(self):
|
||||||
@@ -516,9 +529,7 @@ def _current_root(self):
|
|||||||
|
|
||||||
def _next_root(self, specs):
|
def _next_root(self, specs):
|
||||||
content_hash = self.content_hash(specs)
|
content_hash = self.content_hash(specs)
|
||||||
root_dir = os.path.dirname(self.root)
|
return os.path.join(self._impl_dir, content_hash)
|
||||||
root_name = os.path.basename(self.root)
|
|
||||||
return os.path.join(root_dir, '._%s' % root_name, content_hash)
|
|
||||||
|
|
||||||
def content_hash(self, specs):
|
def content_hash(self, specs):
|
||||||
d = syaml.syaml_dict([
|
d = syaml.syaml_dict([
|
||||||
@@ -649,12 +660,25 @@ def regenerate(self, all_specs, roots):
|
|||||||
raise SpackEnvironmentViewError(msg)
|
raise SpackEnvironmentViewError(msg)
|
||||||
os.rename(tmp_symlink_name, self.root)
|
os.rename(tmp_symlink_name, self.root)
|
||||||
|
|
||||||
# remove old_root
|
# If we have more than the number of views to keep in the directory
|
||||||
if old_root and os.path.exists(old_root):
|
# delete the oldest until the correct number remain. Do not count
|
||||||
|
# things that aren't named as a root would be.
|
||||||
|
roots = [os.path.join(self._impl_dir, entry)
|
||||||
|
for entry in os.listdir(self._impl_dir)
|
||||||
|
if re.match(r'[a-z0-9]{32}', entry)]
|
||||||
|
|
||||||
|
num_to_remove = len(roots) - self.keep
|
||||||
|
if num_to_remove <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# sorting by st_mtime means the oldest come first
|
||||||
|
oldest_roots = sorted(roots, key=lambda path: os.stat(path).st_mtime)
|
||||||
|
for root_to_delete in oldest_roots[:num_to_remove]:
|
||||||
|
# remove old_root
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(old_root)
|
shutil.rmtree(root_to_delete)
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
msg = "Failed to remove old view at %s\n" % old_root
|
msg = "Failed to remove old view at %s\n" % root_to_delete
|
||||||
msg += str(e)
|
msg += str(e)
|
||||||
tty.warn(msg)
|
tty.warn(msg)
|
||||||
|
|
||||||
|
@@ -126,6 +126,10 @@
|
|||||||
'type': 'string',
|
'type': 'string',
|
||||||
'pattern': '(roots|all)',
|
'pattern': '(roots|all)',
|
||||||
},
|
},
|
||||||
|
'keep': {
|
||||||
|
'type': 'integer',
|
||||||
|
'minimum': 1,
|
||||||
|
},
|
||||||
'select': {
|
'select': {
|
||||||
'type': 'array',
|
'type': 'array',
|
||||||
'items': {
|
'items': {
|
||||||
|
@@ -2581,6 +2581,36 @@ def test_multiple_modules_post_env_hook(tmpdir, install_mockery, mock_fetch):
|
|||||||
assert spec.prefix in full_contents
|
assert spec.prefix in full_contents
|
||||||
|
|
||||||
|
|
||||||
|
def test_view_keep_number(tmpdir, install_mockery, mock_fetch):
|
||||||
|
spack_yaml = """
|
||||||
|
spack:
|
||||||
|
specs:
|
||||||
|
- trivial-install-test-package
|
||||||
|
view:
|
||||||
|
default:
|
||||||
|
root: view
|
||||||
|
keep: 1
|
||||||
|
"""
|
||||||
|
_env_create('test', StringIO(spack_yaml))
|
||||||
|
|
||||||
|
with ev.read('test') as e:
|
||||||
|
install()
|
||||||
|
|
||||||
|
# Add something that will affect the view hash
|
||||||
|
e.default_view.exclude = ['gcc']
|
||||||
|
e.regenerate_views()
|
||||||
|
|
||||||
|
view_path = e.default_view._impl_dir
|
||||||
|
|
||||||
|
assert len(os.listdir(view_path)) == 1
|
||||||
|
|
||||||
|
with ev.read('test') as e:
|
||||||
|
e.default_view.keep = 2
|
||||||
|
e.regenerate_views()
|
||||||
|
|
||||||
|
assert len(os.listdir(view_path)) == 2
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.regression('24148')
|
@pytest.mark.regression('24148')
|
||||||
def test_virtual_spec_concretize_together(tmpdir):
|
def test_virtual_spec_concretize_together(tmpdir):
|
||||||
# An environment should permit to concretize "mpi"
|
# An environment should permit to concretize "mpi"
|
||||||
|
Reference in New Issue
Block a user