From c93e465134b06b8f18717fc664ac328858bad95c Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 8 May 2022 01:19:44 -0700 Subject: [PATCH] full hash: fix uninstall and gc with full hash DB The database now stores full hashes, so we need to adjust the criteria we use to determine if something can be uninstalled. Specifically, it's ok to uninstall thing that have remaining build-only dependents. --- lib/spack/spack/cmd/uninstall.py | 18 ++++++++++++++---- lib/spack/spack/database.py | 7 +++++++ lib/spack/spack/package.py | 6 +++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py index ce3d6f7dab4..f7fbd67754e 100644 --- a/lib/spack/spack/cmd/uninstall.py +++ b/lib/spack/spack/cmd/uninstall.py @@ -225,15 +225,25 @@ def do_uninstall(env, specs, force): # A package is ready to be uninstalled when nothing else references it, # unless we are requested to force uninstall it. - is_ready = lambda x: not spack.store.db.query_by_spec_hash(x)[1].ref_count - if force: - is_ready = lambda x: True + def is_ready(dag_hash): + if force: + return True + + _, record = spack.store.db.query_by_spec_hash(dag_hash) + if not record.ref_count: + return True + + # If this spec is only used as a build dependency, we can uninstall + return all( + dspec.deptypes == ("build",) + for dspec in record.spec.edges_from_dependents() + ) while packages: ready = [x for x in packages if is_ready(x.spec.dag_hash())] if not ready: msg = 'unexpected error [cannot proceed uninstalling specs with' \ - ' remaining dependents {0}]' + ' remaining link or run dependents {0}]' msg = msg.format(', '.join(x.name for x in packages)) raise spack.error.SpackError(msg) diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py index 06389cad780..1b10965a42d 100644 --- a/lib/spack/spack/database.py +++ b/lib/spack/spack/database.py @@ -691,6 +691,13 @@ def db_for_spec_hash(self, hash_key): return db def query_by_spec_hash(self, hash_key, data=None): + """Get a spec for hash, and whether it's installed upstream. + + Return: + (tuple): (bool, optional InstallRecord): bool tells us whether + the spec is installed upstream. Its InstallRecord is also + returned if it's installed at all; otherwise None. + """ if data and hash_key in data: return False, data[hash_key] if not data: diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 9fc227baecf..ce8f2add090 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -2371,7 +2371,11 @@ def uninstall_by_spec(spec, force=False, deprecator=None): if not force: dependents = spack.store.db.installed_relatives( - spec, 'parents', True) + spec, + direction='parents', + transitive=True, + deptype=("link", "run"), + ) if dependents: raise PackageStillNeededError(spec, dependents)