From 7713dd4063ed446173fd928c37a9d28bd70f8d0b Mon Sep 17 00:00:00 2001 From: Gregory Becker Date: Thu, 3 Jun 2021 13:50:22 -0700 Subject: [PATCH] keep 5 views around by default --- lib/spack/spack/environment.py | 38 +++++++++++++++++++++++++++------- lib/spack/spack/schema/env.py | 4 ++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py index c41d567bce1..8df066d5713 100644 --- a/lib/spack/spack/environment.py +++ b/lib/spack/spack/environment.py @@ -453,15 +453,19 @@ def _eval_conditional(string): return eval(string, valid_variables) +_default_keep = 5 + + class ViewDescriptor(object): 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.root = spack.util.path.canonicalize_path(root) self.projections = projections self.select = select self.exclude = exclude self.link = link + self.keep = keep def select_fn(self, spec): return any(spec.satisfies(s) for s in self.select) @@ -474,7 +478,8 @@ def __eq__(self, other): self.projections == other.projections, self.select == other.select, self.exclude == other.exclude, - self.link == other.link]) + self.link == other.link, + self.keep == other.keep]) def to_dict(self): ret = syaml.syaml_dict([('root', self.root)]) @@ -491,6 +496,8 @@ def to_dict(self): ret['exclude'] = self.exclude if self.link != default_view_link: ret['link'] = self.link + if self.keep != _default_keep: + ret['keep'] = self.keep return ret @staticmethod @@ -500,7 +507,8 @@ def from_dict(base_path, d): d.get('projections', {}), d.get('select', []), d.get('exclude', []), - d.get('link', default_view_link)) + d.get('link', default_view_link), + d.get('keep', _default_keep)) @property def _current_root(self): @@ -636,7 +644,7 @@ def regenerate(self, all_specs, roots): with_dependencies=False) # create symlink from tmpname to new_root - root_dirname = os.path.dirname(self.root) + root_dirname, root_basename = os.path.split(self.root) tmp_symlink_name = os.path.join(root_dirname, '._view_link') if os.path.exists(tmp_symlink_name): os.unlink(tmp_symlink_name) @@ -649,12 +657,26 @@ def regenerate(self, all_specs, roots): raise SpackEnvironmentViewError(msg) os.rename(tmp_symlink_name, self.root) - # remove old_root - if old_root and os.path.exists(old_root): + # If we have more than the number of views to keep in the directory + # delete the oldest until the correct number remain. Do not count + # things that aren't named as a root would be. + root_impl_dir = os.path.join(root_dirname, '._%s' % root_basename) + roots = [os.path.join(root_impl_dir, entry) + for entry in os.listdir(root_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: - shutil.rmtree(old_root) + shutil.rmtree(root_to_delete) 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) tty.warn(msg) diff --git a/lib/spack/spack/schema/env.py b/lib/spack/spack/schema/env.py index 82971505e47..88b9bda4ae4 100644 --- a/lib/spack/spack/schema/env.py +++ b/lib/spack/spack/schema/env.py @@ -126,6 +126,10 @@ 'type': 'string', 'pattern': '(roots|all)', }, + 'keep': { + 'type': 'integer', + 'minimum': 1, + }, 'select': { 'type': 'array', 'items': {