uninstall : added recursive option
This commit is contained in:
parent
38ea75e8ca
commit
e0f463c4f9
1 changed files with 101 additions and 50 deletions
|
@ -23,19 +23,24 @@
|
||||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.tty.colify import colify
|
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
import spack.repository
|
import spack.repository
|
||||||
from spack.cmd.find import display_specs
|
from spack.cmd.find import display_specs
|
||||||
from spack.package import PackageStillNeededError
|
from spack.package import PackageStillNeededError
|
||||||
|
|
||||||
description="Remove an installed package"
|
description = "Remove an installed package"
|
||||||
|
|
||||||
|
error_message = """You can either:
|
||||||
|
a) Use a more specific spec, or
|
||||||
|
b) use spack uninstall -a to uninstall ALL matching specs.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def setup_parser(subparser):
|
def setup_parser(subparser):
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
|
@ -47,7 +52,78 @@ def setup_parser(subparser):
|
||||||
"supplied spec. i.e., if you say uninstall libelf, ALL versions of " +
|
"supplied spec. i.e., if you say uninstall libelf, ALL versions of " +
|
||||||
"libelf are uninstalled. This is both useful and dangerous, like rm -r.")
|
"libelf are uninstalled. This is both useful and dangerous, like rm -r.")
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'packages', nargs=argparse.REMAINDER, help="specs of packages to uninstall")
|
'-r', '--recursive', action='store_true', dest='recursive',
|
||||||
|
help='Uninstall all the packages that depends on the ones for which we required explicit removal.'
|
||||||
|
|
||||||
|
)
|
||||||
|
subparser.add_argument('packages', nargs=argparse.REMAINDER, help="specs of packages to uninstall")
|
||||||
|
|
||||||
|
|
||||||
|
def concretize_specs(specs, allow_multiple_matches=False, force=False):
|
||||||
|
"""
|
||||||
|
Returns a list of specs matching the non necessarily concretized specs given from cli
|
||||||
|
|
||||||
|
Args:
|
||||||
|
specs: list of specs to be matched against installed packages
|
||||||
|
allow_multiple_matches : boolean (if True multiple matches for each item in specs are admitted)
|
||||||
|
|
||||||
|
Return:
|
||||||
|
list of specs
|
||||||
|
"""
|
||||||
|
specs_from_cli = [] # List of specs that match expressions given via command line
|
||||||
|
has_errors = False
|
||||||
|
for spec in specs:
|
||||||
|
matching = spack.installed_db.query(spec)
|
||||||
|
# For each spec provided, make sure it refers to only one package.
|
||||||
|
# Fail and ask user to be unambiguous if it doesn't
|
||||||
|
if not allow_multiple_matches and len(matching) > 1:
|
||||||
|
tty.error("%s matches multiple packages:" % spec)
|
||||||
|
print()
|
||||||
|
display_specs(matching, long=True)
|
||||||
|
print()
|
||||||
|
has_errors = True
|
||||||
|
|
||||||
|
# No installed package matches the query
|
||||||
|
if len(matching) == 0 and not force:
|
||||||
|
tty.error("%s does not match any installed packages." % spec)
|
||||||
|
has_errors = True
|
||||||
|
|
||||||
|
specs_from_cli.extend(matching)
|
||||||
|
if has_errors:
|
||||||
|
tty.die(error_message)
|
||||||
|
|
||||||
|
return specs_from_cli
|
||||||
|
|
||||||
|
|
||||||
|
def installed_dependents(specs):
|
||||||
|
dependents = {}
|
||||||
|
for item in specs:
|
||||||
|
lst = [x for x in item.package.installed_dependents if x not in specs]
|
||||||
|
if lst:
|
||||||
|
dependents[item] = lst
|
||||||
|
return dependents
|
||||||
|
|
||||||
|
|
||||||
|
def do_uninstall(specs, force):
|
||||||
|
specs = list(set(specs)) # Make specs unique
|
||||||
|
packages = []
|
||||||
|
for item in specs:
|
||||||
|
try:
|
||||||
|
# should work if package is known to spack
|
||||||
|
packages.append(item.package)
|
||||||
|
except spack.repository.UnknownPackageError as e:
|
||||||
|
# The package.py file has gone away -- but still
|
||||||
|
# want to uninstall.
|
||||||
|
spack.Package(item).do_uninstall(force=True)
|
||||||
|
|
||||||
|
# Sort packages to be uninstalled by the number of installed dependents
|
||||||
|
# This ensures we do things in the right order
|
||||||
|
def num_installed_deps(pkg):
|
||||||
|
return len(pkg.installed_dependents)
|
||||||
|
|
||||||
|
packages.sort(key=num_installed_deps)
|
||||||
|
for item in packages:
|
||||||
|
item.do_uninstall(force=force)
|
||||||
|
|
||||||
|
|
||||||
def uninstall(parser, args):
|
def uninstall(parser, args):
|
||||||
|
@ -56,50 +132,25 @@ def uninstall(parser, args):
|
||||||
|
|
||||||
with spack.installed_db.write_transaction():
|
with spack.installed_db.write_transaction():
|
||||||
specs = spack.cmd.parse_specs(args.packages)
|
specs = spack.cmd.parse_specs(args.packages)
|
||||||
|
# Gets the list of installed specs that match the ones give via cli
|
||||||
|
uninstall_list = concretize_specs(specs, args.all, args.force) # takes care of '-a' is given in the cli
|
||||||
|
dependent_list = installed_dependents(uninstall_list) # takes care of '-r'
|
||||||
|
|
||||||
# For each spec provided, make sure it refers to only one package.
|
# There are dependents but recursive uninstall wasn't a requirement
|
||||||
# Fail and ask user to be unambiguous if it doesn't
|
has_error = False
|
||||||
pkgs = []
|
if dependent_list and not args.recursive and not args.force:
|
||||||
for spec in specs:
|
for spec, lst in dependent_list.items():
|
||||||
matching_specs = spack.installed_db.query(spec)
|
tty.error("Will not uninstall %s" % spec.format("$_$@$%@$#", color=True))
|
||||||
if not args.all and len(matching_specs) > 1:
|
|
||||||
tty.error("%s matches multiple packages:" % spec)
|
|
||||||
print()
|
|
||||||
display_specs(matching_specs, long=True)
|
|
||||||
print()
|
|
||||||
print("You can either:")
|
|
||||||
print(" a) Use a more specific spec, or")
|
|
||||||
print(" b) use spack uninstall -a to uninstall ALL matching specs.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if len(matching_specs) == 0:
|
|
||||||
if args.force: continue
|
|
||||||
tty.die("%s does not match any installed packages." % spec)
|
|
||||||
|
|
||||||
for s in matching_specs:
|
|
||||||
try:
|
|
||||||
# should work if package is known to spack
|
|
||||||
pkgs.append(s.package)
|
|
||||||
except spack.repository.UnknownPackageError as e:
|
|
||||||
# The package.py file has gone away -- but still
|
|
||||||
# want to uninstall.
|
|
||||||
spack.Package(s).do_uninstall(force=True)
|
|
||||||
|
|
||||||
# Sort packages to be uninstalled by the number of installed dependents
|
|
||||||
# This ensures we do things in the right order
|
|
||||||
def num_installed_deps(pkg):
|
|
||||||
return len(pkg.installed_dependents)
|
|
||||||
pkgs.sort(key=num_installed_deps)
|
|
||||||
|
|
||||||
# Uninstall packages in order now.
|
|
||||||
for pkg in pkgs:
|
|
||||||
try:
|
|
||||||
pkg.do_uninstall(force=args.force)
|
|
||||||
except PackageStillNeededError as e:
|
|
||||||
tty.error("Will not uninstall %s" % e.spec.format("$_$@$%@$#", color=True))
|
|
||||||
print('')
|
print('')
|
||||||
print("The following packages depend on it:")
|
print("The following packages depend on it:")
|
||||||
display_specs(e.dependents, long=True)
|
display_specs(lst, long=True)
|
||||||
print('')
|
print('')
|
||||||
print("You can use spack uninstall -f to force this action.")
|
has_error = True
|
||||||
sys.exit(1)
|
elif args.recursive:
|
||||||
|
for key, lst in dependent_list.items():
|
||||||
|
uninstall_list.extend(lst)
|
||||||
|
|
||||||
|
if has_error:
|
||||||
|
tty.die('You can use spack uninstall -f to force this action')
|
||||||
|
# Uninstall everything on the list
|
||||||
|
do_uninstall(uninstall_list, args.force)
|
||||||
|
|
Loading…
Reference in a new issue