environments: synchronize read and uninstall (#14676)
* `Environment.__init__` is now synchronized with all writing operations * `spack uninstall` now synchronizes its updates to any associated environment * A side effect of this is that the environment is no longer updated piecemeal as specs are uninstalled - all specs are removed from the environment before they are uninstalled
This commit is contained in:
parent
488e25ea34
commit
85ef1be780
@ -6,6 +6,7 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import itertools
|
||||||
|
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
import spack.environment as ev
|
import spack.environment as ev
|
||||||
@ -205,9 +206,6 @@ def do_uninstall(env, specs, force):
|
|||||||
# want to uninstall.
|
# want to uninstall.
|
||||||
spack.package.Package.uninstall_by_spec(item, force=True)
|
spack.package.Package.uninstall_by_spec(item, force=True)
|
||||||
|
|
||||||
if env:
|
|
||||||
_remove_from_env(item, env)
|
|
||||||
|
|
||||||
# A package is ready to be uninstalled when nothing else references it,
|
# A package is ready to be uninstalled when nothing else references it,
|
||||||
# unless we are requested to force uninstall 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
|
is_ready = lambda x: not spack.store.db.query_by_spec_hash(x)[1].ref_count
|
||||||
@ -226,10 +224,6 @@ def do_uninstall(env, specs, force):
|
|||||||
for item in ready:
|
for item in ready:
|
||||||
item.do_uninstall(force=force)
|
item.do_uninstall(force=force)
|
||||||
|
|
||||||
# write any changes made to the active environment
|
|
||||||
if env:
|
|
||||||
env.write()
|
|
||||||
|
|
||||||
|
|
||||||
def get_uninstall_list(args, specs, env):
|
def get_uninstall_list(args, specs, env):
|
||||||
# Gets the list of installed specs that match the ones give via cli
|
# Gets the list of installed specs that match the ones give via cli
|
||||||
@ -317,9 +311,13 @@ def uninstall_specs(args, specs):
|
|||||||
if not args.yes_to_all:
|
if not args.yes_to_all:
|
||||||
confirm_removal(anything_to_do)
|
confirm_removal(anything_to_do)
|
||||||
|
|
||||||
# just force-remove things in the remove list
|
if env:
|
||||||
for spec in remove_list:
|
# Remove all the specs that are supposed to be uninstalled or just
|
||||||
_remove_from_env(spec, env)
|
# removed.
|
||||||
|
with env.write_transaction():
|
||||||
|
for spec in itertools.chain(remove_list, uninstall_list):
|
||||||
|
_remove_from_env(spec, env)
|
||||||
|
env.write()
|
||||||
|
|
||||||
# Uninstall everything on the list
|
# Uninstall everything on the list
|
||||||
do_uninstall(env, uninstall_list, args.force)
|
do_uninstall(env, uninstall_list, args.force)
|
||||||
|
@ -567,6 +567,9 @@ def __init__(self, path, init_file=None, with_view=None):
|
|||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
if init_file:
|
if init_file:
|
||||||
|
# If we are creating the environment from an init file, we don't
|
||||||
|
# need to lock, because there are no Spack operations that alter
|
||||||
|
# the init file.
|
||||||
with fs.open_if_filename(init_file) as f:
|
with fs.open_if_filename(init_file) as f:
|
||||||
if hasattr(f, 'name') and f.name.endswith('.lock'):
|
if hasattr(f, 'name') and f.name.endswith('.lock'):
|
||||||
self._read_manifest(default_manifest_yaml)
|
self._read_manifest(default_manifest_yaml)
|
||||||
@ -575,7 +578,8 @@ def __init__(self, path, init_file=None, with_view=None):
|
|||||||
else:
|
else:
|
||||||
self._read_manifest(f, raw_yaml=default_manifest_yaml)
|
self._read_manifest(f, raw_yaml=default_manifest_yaml)
|
||||||
else:
|
else:
|
||||||
self._read()
|
with lk.ReadTransaction(self.txlock):
|
||||||
|
self._read()
|
||||||
|
|
||||||
if with_view is False:
|
if with_view is False:
|
||||||
self.views = {}
|
self.views = {}
|
||||||
@ -1472,13 +1476,13 @@ def write(self, regenerate_views=True):
|
|||||||
|
|
||||||
# Remove yaml sections that are shadowing defaults
|
# Remove yaml sections that are shadowing defaults
|
||||||
# construct garbage path to ensure we don't find a manifest by accident
|
# construct garbage path to ensure we don't find a manifest by accident
|
||||||
bare_env = Environment(os.path.join(self.manifest_path, 'garbage'),
|
with fs.temp_cwd() as env_dir:
|
||||||
with_view=self.view_path_default)
|
bare_env = Environment(env_dir, with_view=self.view_path_default)
|
||||||
keys_present = list(yaml_dict.keys())
|
keys_present = list(yaml_dict.keys())
|
||||||
for key in keys_present:
|
for key in keys_present:
|
||||||
if yaml_dict[key] == config_dict(bare_env.yaml).get(key, None):
|
if yaml_dict[key] == config_dict(bare_env.yaml).get(key, None):
|
||||||
if key not in raw_yaml_dict:
|
if key not in raw_yaml_dict:
|
||||||
del yaml_dict[key]
|
del yaml_dict[key]
|
||||||
|
|
||||||
# if all that worked, write out the manifest file at the top level
|
# if all that worked, write out the manifest file at the top level
|
||||||
# Only actually write if it has changed or was never written
|
# Only actually write if it has changed or was never written
|
||||||
|
Loading…
Reference in New Issue
Block a user