Compare commits
1 Commits
develop
...
features/d
Author | SHA1 | Date |
---|---|---|
Gregory Becker | cf7d625bdb |
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.cmd
|
||||
|
||||
|
||||
display_args = {"long": True, "show_flags": False, "variants": False, "indent": 4}
|
||||
|
||||
|
||||
def confirm_action(specs: List[spack.spec.Spec], participle: str, noun: str):
|
||||
"""Display the list of specs to be acted on and ask for confirmation.
|
||||
|
||||
Args:
|
||||
specs: specs to be removed
|
||||
participle: action expressed as a participle, e.g. "uninstalled"
|
||||
noun: action expressed as a noun, e.g. "uninstallation"
|
||||
"""
|
||||
tty.msg(f"The following {len(specs)} packages will be {participle}:\n")
|
||||
spack.cmd.display_specs(specs, **display_args)
|
||||
print("")
|
||||
answer = tty.get_yes_or_no("Do you want to proceed?", default=False)
|
||||
if not answer:
|
||||
tty.msg(f"Aborting {noun}")
|
||||
sys.exit(0)
|
|
@ -0,0 +1,157 @@
|
|||
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import sys
|
||||
from typing import List, Optional
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.cmd.common.confirmation as confirmation
|
||||
import spack.environment as ev
|
||||
import spack.spec
|
||||
import spack.traverse as traverse
|
||||
|
||||
description = "remove specs from the concretized lockfile of an environment"
|
||||
section = "environments"
|
||||
level = "short"
|
||||
|
||||
error_message = """You can either:
|
||||
a) use a more specific spec, or
|
||||
b) specify the spec by its hash (e.g. `spack deconcretize /hash`), or
|
||||
c) use `spack deconcretize --all` to deconcretize ALL matching specs.
|
||||
"""
|
||||
|
||||
# Arguments for display_specs when we find ambiguity
|
||||
display_args = {"long": True, "show_flags": False, "variants": False, "indent": 4}
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
subparser.add_argument(
|
||||
"-f",
|
||||
"--force",
|
||||
action="store_true",
|
||||
dest="force",
|
||||
help="remove regardless of whether other packages or environments " "depend on this one",
|
||||
)
|
||||
arguments.add_common_arguments(subparser, ["recurse_dependents", "yes_to_all", "specs"])
|
||||
subparser.add_argument(
|
||||
"-a",
|
||||
"--all",
|
||||
action="store_true",
|
||||
dest="all",
|
||||
help="deconcretize ALL specs that match each supplied spec",
|
||||
)
|
||||
|
||||
|
||||
def find_matching_specs(
|
||||
env: ev.Environment, specs: List[spack.spec.Spec], allow_multiple_matches: bool = False
|
||||
):
|
||||
"""Returns a list of concrete specs in the environment matching the abstract specs from CLI
|
||||
|
||||
Args:
|
||||
env: active environment
|
||||
specs: list of specs to be matched against concrete environment
|
||||
allow_multiple_matches: if True mulitple matches are permitted
|
||||
|
||||
Return:
|
||||
list: list of specs
|
||||
"""
|
||||
matching_specs = []
|
||||
has_errors = False
|
||||
for spec in specs:
|
||||
if spec is any:
|
||||
matching = [s for _, s in env.concretized_specs()]
|
||||
else:
|
||||
matching = [s for _, s in env.concretized_specs() if s.satisfies(spec)]
|
||||
|
||||
if not allow_multiple_matches and len(matching) > 1:
|
||||
tty.error(f"{spec} matches multiple concrete specs:")
|
||||
sys.stderr.write("\n")
|
||||
spack.cmd.display_specs(matching, output=sys.stderr, **display_args)
|
||||
sys.stderr.write("\n")
|
||||
sys.stderr.flush()
|
||||
has_errors = True
|
||||
|
||||
if len(matching) == 0 and spec is not any:
|
||||
tty.die(f"{spec} does not match any concrete spec.")
|
||||
|
||||
matching_specs.extend(matching)
|
||||
|
||||
if has_errors:
|
||||
tty.die(error_message)
|
||||
|
||||
return matching_specs
|
||||
|
||||
|
||||
def concrete_dependents(
|
||||
specs: List[spack.spec.Spec], env: ev.Environment
|
||||
) -> List[spack.spec.Spec]:
|
||||
# Note this traversal will not return any spec in the original list
|
||||
return [
|
||||
spec
|
||||
for spec in traverse.traverse_nodes(
|
||||
specs,
|
||||
root=False,
|
||||
order="breadth",
|
||||
cover="nodes",
|
||||
direction="parents",
|
||||
key=lambda s: s.dag_hash(),
|
||||
)
|
||||
if spec.dag_hash() in env.concretized_order
|
||||
]
|
||||
|
||||
|
||||
def get_deconcretize_list(args, specs, env):
|
||||
matching_specs = find_matching_specs(env, specs, args.all)
|
||||
dependent_specs = concrete_dependents(matching_specs, env)
|
||||
to_deconcretize = matching_specs + dependent_specs if args.dependents else matching_specs
|
||||
|
||||
dangling_dependents = dependent_specs and not args.dependents
|
||||
has_error = not args.force and dangling_dependents
|
||||
|
||||
if has_error:
|
||||
tty.info("Refusing to deconcretize the following specs")
|
||||
spack.cmd.display_specs(matching_specs, **display_args)
|
||||
print()
|
||||
tty.info("The following dependents are still concrete in the environment:")
|
||||
spack.cmd.display_specs(dependent_specs, **display_args)
|
||||
tty.die(
|
||||
"There are still dependents.",
|
||||
"use `spack deconcretize --dependents` to deconcretize dependents too",
|
||||
"use `spack deconcretize --force` to override",
|
||||
)
|
||||
|
||||
return to_deconcretize
|
||||
|
||||
|
||||
def deconcretize_specs(args, specs):
|
||||
env = spack.cmd.require_active_env(cmd_name="deconcretize")
|
||||
|
||||
deconcretize_list = get_deconcretize_list(args, specs, env)
|
||||
|
||||
if not deconcretize_list:
|
||||
tty.warn("There are no concrete specs to deconcretize.")
|
||||
return
|
||||
|
||||
if not args.yes_to_all:
|
||||
confirmation.confirm_action(deconcretize_list, "deconcretized", "deconcretization")
|
||||
|
||||
with env.write_transaction():
|
||||
for spec in deconcretize_list:
|
||||
env.deconcretize(spec)
|
||||
env.write()
|
||||
|
||||
|
||||
def deconcretize(parser, args):
|
||||
if not args.specs and not args.all:
|
||||
tty.die(
|
||||
"deconcretize requires at least one spec argument.",
|
||||
" Use `spack deconcretize --all` to deconcretize ALL specs.",
|
||||
)
|
||||
|
||||
specs = spack.cmd.parse_specs(args.specs) if args.specs else [any]
|
||||
deconcretize_specs(args, specs)
|
|
@ -6,6 +6,7 @@
|
|||
import llnl.util.tty as tty
|
||||
|
||||
import spack.cmd.common.arguments
|
||||
import spack.cmd.common.confirmation
|
||||
import spack.cmd.uninstall
|
||||
import spack.environment as ev
|
||||
import spack.store
|
||||
|
@ -41,6 +42,6 @@ def gc(parser, args):
|
|||
return
|
||||
|
||||
if not args.yes_to_all:
|
||||
spack.cmd.uninstall.confirm_removal(specs)
|
||||
spack.cmd.common.confirmation.confirm_action(specs, "uninstalled", "uninstallation")
|
||||
|
||||
spack.cmd.uninstall.do_uninstall(specs, force=False)
|
||||
|
|
|
@ -11,10 +11,9 @@ from llnl.util.tty.colify import colify
|
|||
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments as arguments
|
||||
import spack.cmd.common.confirmation as confirmation
|
||||
import spack.environment as ev
|
||||
import spack.error
|
||||
import spack.package_base
|
||||
import spack.repo
|
||||
import spack.spec
|
||||
import spack.store
|
||||
import spack.traverse as traverse
|
||||
|
@ -278,7 +277,7 @@ def uninstall_specs(args, specs):
|
|||
return
|
||||
|
||||
if not args.yes_to_all:
|
||||
confirm_removal(uninstall_list)
|
||||
confirmation.confirm_action(uninstall_list, "uninstalled", "uninstallation")
|
||||
|
||||
# Uninstall everything on the list
|
||||
do_uninstall(uninstall_list, args.force)
|
||||
|
@ -292,21 +291,6 @@ def uninstall_specs(args, specs):
|
|||
env.regenerate_views()
|
||||
|
||||
|
||||
def confirm_removal(specs: List[spack.spec.Spec]):
|
||||
"""Display the list of specs to be removed and ask for confirmation.
|
||||
|
||||
Args:
|
||||
specs: specs to be removed
|
||||
"""
|
||||
tty.msg("The following {} packages will be uninstalled:\n".format(len(specs)))
|
||||
spack.cmd.display_specs(specs, **display_args)
|
||||
print("")
|
||||
answer = tty.get_yes_or_no("Do you want to proceed?", default=False)
|
||||
if not answer:
|
||||
tty.msg("Aborting uninstallation")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def uninstall(parser, args):
|
||||
if not args.specs and not args.all:
|
||||
tty.die(
|
||||
|
|
|
@ -1308,7 +1308,7 @@ class Environment:
|
|||
|
||||
# Remove concrete specs that no longer correlate to a user spec
|
||||
for spec in set(self.concretized_user_specs) - set(self.user_specs):
|
||||
self.deconcretize(spec)
|
||||
self.deconcretize(spec, concrete=False)
|
||||
|
||||
# Pick the right concretization strategy
|
||||
if self.unify == "when_possible":
|
||||
|
@ -1323,11 +1323,29 @@ class Environment:
|
|||
msg = "concretization strategy not implemented [{0}]"
|
||||
raise SpackEnvironmentError(msg.format(self.unify))
|
||||
|
||||
def deconcretize(self, spec):
|
||||
def deconcretize(self, spec, concrete=True):
|
||||
# If concrete, find all instances of concrete spec
|
||||
# Else, find single instance of user spec
|
||||
# the distinction is only relevant if multiple roots concretize
|
||||
# to the same spec
|
||||
|
||||
# spec has to be a root of the environment
|
||||
index = self.concretized_user_specs.index(spec)
|
||||
dag_hash = self.concretized_order.pop(index)
|
||||
del self.concretized_user_specs[index]
|
||||
if concrete:
|
||||
dag_hash = spec.dag_hash()
|
||||
indices = [
|
||||
i
|
||||
for i in range(len(self.concretized_order))
|
||||
if self.concretized_order[i] == dag_hash
|
||||
]
|
||||
|
||||
for index in indices:
|
||||
del self.concretized_order[index]
|
||||
del self.concretized_user_specs[index]
|
||||
else:
|
||||
index = self.concretized_user_specs.index(spec)
|
||||
dag_hash = self.concretized_order.pop(index)
|
||||
|
||||
del self.concretized_user_specs[index]
|
||||
|
||||
# If this was the only user spec that concretized to this concrete spec, remove it
|
||||
if dag_hash not in self.concretized_order:
|
||||
|
|
Loading…
Reference in New Issue