env: move env uninstall
into spack uninstall
- uninstall now: - restricts its spec search to the current environment - removes uninstalled specs from the current environment - reports envs that still need specs you're trying to uninstall - removed spack env uninstall command - updated tests
This commit is contained in:
parent
7136274f4b
commit
26a55ff749
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.lang import attr_setdefault, index_by
|
from llnl.util.lang import attr_setdefault, index_by
|
||||||
@ -207,6 +208,7 @@ def display_specs(specs, args=None, **kwargs):
|
|||||||
namespace (bool): Print namespaces along with names
|
namespace (bool): Print namespaces along with names
|
||||||
show_flags (bool): Show compiler flags with specs
|
show_flags (bool): Show compiler flags with specs
|
||||||
variants (bool): Show variants with specs
|
variants (bool): Show variants with specs
|
||||||
|
indent (int): indent each line this much
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def get_arg(name, default=None):
|
def get_arg(name, default=None):
|
||||||
@ -225,6 +227,9 @@ def get_arg(name, default=None):
|
|||||||
full_compiler = get_arg('show_full_compiler', False)
|
full_compiler = get_arg('show_full_compiler', False)
|
||||||
variants = get_arg('variants', False)
|
variants = get_arg('variants', False)
|
||||||
|
|
||||||
|
indent = get_arg('indent', 0)
|
||||||
|
ispace = indent * ' '
|
||||||
|
|
||||||
hlen = 7
|
hlen = 7
|
||||||
if get_arg('very_long', False):
|
if get_arg('very_long', False):
|
||||||
hashes = True
|
hashes = True
|
||||||
@ -255,6 +260,7 @@ def get_arg(name, default=None):
|
|||||||
# If they don't have a compiler / architecture attached to them,
|
# If they don't have a compiler / architecture attached to them,
|
||||||
# then skip the header
|
# then skip the header
|
||||||
if architecture is not None or compiler is not None:
|
if architecture is not None or compiler is not None:
|
||||||
|
sys.stdout.write(ispace)
|
||||||
tty.hline(colorize(header), char='-')
|
tty.hline(colorize(header), char='-')
|
||||||
|
|
||||||
specs = index[(architecture, compiler)]
|
specs = index[(architecture, compiler)]
|
||||||
@ -269,7 +275,7 @@ def get_arg(name, default=None):
|
|||||||
|
|
||||||
for abbrv, spec in zip(abbreviated, specs):
|
for abbrv, spec in zip(abbreviated, specs):
|
||||||
prefix = gray_hash(spec, hlen) if hashes else ''
|
prefix = gray_hash(spec, hlen) if hashes else ''
|
||||||
print(prefix + (format % (abbrv, spec.prefix)))
|
print(ispace + prefix + (format % (abbrv, spec.prefix)))
|
||||||
|
|
||||||
elif mode == 'deps':
|
elif mode == 'deps':
|
||||||
for spec in specs:
|
for spec in specs:
|
||||||
@ -290,13 +296,13 @@ def fmt(s):
|
|||||||
|
|
||||||
return string
|
return string
|
||||||
|
|
||||||
colify(fmt(s) for s in specs)
|
colify((fmt(s) for s in specs), indent=indent)
|
||||||
# Print one entry per line if including flags
|
# Print one entry per line if including flags
|
||||||
else:
|
else:
|
||||||
for spec in specs:
|
for spec in specs:
|
||||||
# Print the hash if necessary
|
# Print the hash if necessary
|
||||||
hsh = gray_hash(spec, hlen) + ' ' if hashes else ''
|
hsh = gray_hash(spec, hlen) + ' ' if hashes else ''
|
||||||
print(hsh + spec.cformat(format_string) + '\n')
|
print(ispace + hsh + spec.cformat(format_string))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -56,7 +56,7 @@ def _specs(self, **kwargs):
|
|||||||
# only its installed packages.
|
# only its installed packages.
|
||||||
env = spack.environment.active
|
env = spack.environment.active
|
||||||
if env:
|
if env:
|
||||||
kwargs['hashes'] = set(env.specs_by_hash.keys())
|
kwargs['hashes'] = set(env.all_hashes())
|
||||||
|
|
||||||
# return everything for an empty query.
|
# return everything for an empty query.
|
||||||
if not qspecs:
|
if not qspecs:
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
['list', 'ls'],
|
['list', 'ls'],
|
||||||
['status', 'st'],
|
['status', 'st'],
|
||||||
'loads',
|
'loads',
|
||||||
'uninstall',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -234,7 +233,7 @@ def env_remove(args):
|
|||||||
for env_name in args.env:
|
for env_name in args.env:
|
||||||
env = ev.disambiguate(env_name)
|
env = ev.disambiguate(env_name)
|
||||||
|
|
||||||
if ev.active and ev.active.path == env.path:
|
if env.active:
|
||||||
tty.die("Environment %s can't be removed while activated.")
|
tty.die("Environment %s can't be removed while activated.")
|
||||||
|
|
||||||
env.destroy()
|
env.destroy()
|
||||||
@ -250,7 +249,7 @@ def env_list_setup_parser(subparser):
|
|||||||
|
|
||||||
|
|
||||||
def env_list(args):
|
def env_list(args):
|
||||||
names = ev.list_environments()
|
names = ev.all_environment_names()
|
||||||
|
|
||||||
color_names = []
|
color_names = []
|
||||||
for name in names:
|
for name in names:
|
||||||
@ -268,21 +267,6 @@ def env_list(args):
|
|||||||
colify(color_names, indent=4)
|
colify(color_names, indent=4)
|
||||||
|
|
||||||
|
|
||||||
# REMOVE
|
|
||||||
# env uninstall
|
|
||||||
#
|
|
||||||
def env_uninstall_setup_parser(subparser):
|
|
||||||
"""uninstall packages from an environment"""
|
|
||||||
subparser.add_argument(
|
|
||||||
'env', nargs='?', help='uninstall all packages in this environment')
|
|
||||||
spack.cmd.uninstall.add_common_arguments(subparser)
|
|
||||||
|
|
||||||
|
|
||||||
def env_uninstall(args):
|
|
||||||
env = ev.get_env(args, 'env uninstall')
|
|
||||||
env.uninstall(args)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# env status
|
# env status
|
||||||
#
|
#
|
||||||
@ -308,6 +292,7 @@ def env_status(args):
|
|||||||
hashlen=None if args.very_long else 7,
|
hashlen=None if args.very_long else 7,
|
||||||
install_status=True)
|
install_status=True)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# env loads
|
# env loads
|
||||||
#
|
#
|
||||||
|
@ -8,12 +8,14 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
|
import spack.environment as ev
|
||||||
import spack.package
|
import spack.package
|
||||||
import spack.cmd.common.arguments as arguments
|
import spack.cmd.common.arguments as arguments
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.store
|
import spack.store
|
||||||
|
|
||||||
from llnl.util import tty
|
from llnl.util import tty
|
||||||
|
from llnl.util.tty.colify import colify
|
||||||
|
|
||||||
description = "remove installed packages"
|
description = "remove installed packages"
|
||||||
section = "build"
|
section = "build"
|
||||||
@ -28,14 +30,16 @@
|
|||||||
display_args = {
|
display_args = {
|
||||||
'long': True,
|
'long': True,
|
||||||
'show_flags': True,
|
'show_flags': True,
|
||||||
'variants': True
|
'variants': True,
|
||||||
|
'indent': 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def add_common_arguments(subparser):
|
def add_common_arguments(subparser):
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'-f', '--force', action='store_true', dest='force',
|
'-f', '--force', action='store_true', dest='force',
|
||||||
help="remove regardless of whether other packages depend on this one")
|
help="remove regardless of whether other packages or environments "
|
||||||
|
"depend on this one")
|
||||||
arguments.add_common_arguments(
|
arguments.add_common_arguments(
|
||||||
subparser, ['recurse_dependents', 'yes_to_all'])
|
subparser, ['recurse_dependents', 'yes_to_all'])
|
||||||
|
|
||||||
@ -44,10 +48,12 @@ def setup_parser(subparser):
|
|||||||
add_common_arguments(subparser)
|
add_common_arguments(subparser)
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'-a', '--all', action='store_true', dest='all',
|
'-a', '--all', action='store_true', dest='all',
|
||||||
help="USE CAREFULLY. remove ALL installed packages that match each "
|
help="USE CAREFULLY. Remove ALL installed packages that match each "
|
||||||
"supplied spec. i.e., if you `uninstall --all libelf`,"
|
"supplied spec. i.e., if you `uninstall --all libelf`,"
|
||||||
" ALL versions of `libelf` are uninstalled. if no spec is "
|
" ALL versions of `libelf` are uninstalled. If no spec is "
|
||||||
"supplied all installed software will be uninstalled.")
|
"supplied, all installed packages will be uninstalled. "
|
||||||
|
"If used in an environment, all packages in the environment "
|
||||||
|
"will be uninstalled.")
|
||||||
|
|
||||||
subparser.add_argument(
|
subparser.add_argument(
|
||||||
'packages',
|
'packages',
|
||||||
@ -66,11 +72,13 @@ def find_matching_specs(specs, allow_multiple_matches=False, force=False):
|
|||||||
Return:
|
Return:
|
||||||
list of specs
|
list of specs
|
||||||
"""
|
"""
|
||||||
|
hashes = ev.active.all_hashes() if ev.active else None
|
||||||
|
|
||||||
# List of specs that match expressions given via command line
|
# List of specs that match expressions given via command line
|
||||||
specs_from_cli = []
|
specs_from_cli = []
|
||||||
has_errors = False
|
has_errors = False
|
||||||
for spec in specs:
|
for spec in specs:
|
||||||
matching = spack.store.db.query(spec)
|
matching = spack.store.db.query(spec, hashes=hashes)
|
||||||
# For each spec provided, make sure it refers to only one package.
|
# For each spec provided, make sure it refers to only one package.
|
||||||
# Fail and ask user to be unambiguous if it doesn't
|
# Fail and ask user to be unambiguous if it doesn't
|
||||||
if not allow_multiple_matches and len(matching) > 1:
|
if not allow_multiple_matches and len(matching) > 1:
|
||||||
@ -82,11 +90,14 @@ def find_matching_specs(specs, allow_multiple_matches=False, force=False):
|
|||||||
|
|
||||||
# No installed package matches the query
|
# No installed package matches the query
|
||||||
if len(matching) == 0 and spec is not any:
|
if len(matching) == 0 and spec is not any:
|
||||||
tty.error('{0} does not match any installed packages.'.format(
|
if ev.active:
|
||||||
spec))
|
pkg_type = "packages in environment '%s'" % ev.active.name
|
||||||
has_errors = True
|
else:
|
||||||
|
pkg_type = 'installed packages'
|
||||||
|
tty.die('{0} does not match any {1}.'.format(spec, pkg_type))
|
||||||
|
|
||||||
specs_from_cli.extend(matching)
|
specs_from_cli.extend(matching)
|
||||||
|
|
||||||
if has_errors:
|
if has_errors:
|
||||||
tty.die(error_message)
|
tty.die(error_message)
|
||||||
|
|
||||||
@ -94,14 +105,14 @@ def find_matching_specs(specs, allow_multiple_matches=False, force=False):
|
|||||||
|
|
||||||
|
|
||||||
def installed_dependents(specs):
|
def installed_dependents(specs):
|
||||||
"""Returns a dictionary that maps a spec with a list of its
|
"""Map each spec to a list of its installed dependents.
|
||||||
installed dependents
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
specs: list of specs to be checked for dependents
|
specs (list): list of Specs
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dictionary of installed dependents
|
(dict): mapping from spec to lists of Environments
|
||||||
|
|
||||||
"""
|
"""
|
||||||
dependents = {}
|
dependents = {}
|
||||||
for item in specs:
|
for item in specs:
|
||||||
@ -114,6 +125,28 @@ def installed_dependents(specs):
|
|||||||
return dependents
|
return dependents
|
||||||
|
|
||||||
|
|
||||||
|
def dependent_environments(specs):
|
||||||
|
"""Map each spec to environments that depend on it.
|
||||||
|
|
||||||
|
This excludes the active environment, because we allow uninstalling
|
||||||
|
from the active environment.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
specs (list): list of Specs
|
||||||
|
Returns:
|
||||||
|
(dict): mapping from spec to lists of Environments
|
||||||
|
|
||||||
|
"""
|
||||||
|
dependents = {}
|
||||||
|
for env in ev.all_environments():
|
||||||
|
if not env.active:
|
||||||
|
hashes = set([s.dag_hash() for s in env.all_specs()])
|
||||||
|
for spec in specs:
|
||||||
|
if spec.dag_hash() in hashes:
|
||||||
|
dependents.setdefault(spec, []).append(env)
|
||||||
|
return dependents
|
||||||
|
|
||||||
|
|
||||||
def do_uninstall(specs, force):
|
def do_uninstall(specs, force):
|
||||||
"""
|
"""
|
||||||
Uninstalls all the specs in a list.
|
Uninstalls all the specs in a list.
|
||||||
@ -132,6 +165,12 @@ def do_uninstall(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 ev.active:
|
||||||
|
try:
|
||||||
|
ev.active.remove(item, force=True)
|
||||||
|
except ev.EnvError:
|
||||||
|
pass # ignore errors from specs that are not roots
|
||||||
|
|
||||||
# Sort packages to be uninstalled by the number of installed dependents
|
# Sort packages to be uninstalled by the number of installed dependents
|
||||||
# This ensures we do things in the right order
|
# This ensures we do things in the right order
|
||||||
def num_installed_deps(pkg):
|
def num_installed_deps(pkg):
|
||||||
@ -143,6 +182,10 @@ def num_installed_deps(pkg):
|
|||||||
for item in packages:
|
for item in packages:
|
||||||
item.do_uninstall(force=force)
|
item.do_uninstall(force=force)
|
||||||
|
|
||||||
|
# write any changes made to the active environment
|
||||||
|
if ev.active:
|
||||||
|
ev.active.write()
|
||||||
|
|
||||||
|
|
||||||
def get_uninstall_list(args, specs):
|
def get_uninstall_list(args, specs):
|
||||||
# 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
|
||||||
@ -150,25 +193,54 @@ def get_uninstall_list(args, specs):
|
|||||||
uninstall_list = find_matching_specs(specs, args.all, args.force)
|
uninstall_list = find_matching_specs(specs, args.all, args.force)
|
||||||
|
|
||||||
# Takes care of '-R'
|
# Takes care of '-R'
|
||||||
dependent_list = installed_dependents(uninstall_list)
|
spec_dependents = installed_dependents(uninstall_list)
|
||||||
|
spec_envs = dependent_environments(uninstall_list)
|
||||||
|
|
||||||
|
# Process spec_dependents and update uninstall_list
|
||||||
|
has_error = not args.force and (
|
||||||
|
(spec_dependents and not args.dependents) or
|
||||||
|
spec_envs)
|
||||||
|
|
||||||
|
# say why each problem spec is needed
|
||||||
|
if has_error:
|
||||||
|
specs = set(list(spec_dependents.keys()) + list(spec_envs.keys()))
|
||||||
|
for i, spec in enumerate(sorted(specs)):
|
||||||
|
# space out blocks of reasons
|
||||||
|
if i > 0:
|
||||||
|
print()
|
||||||
|
|
||||||
|
tty.info("Will not uninstall %s" % spec.cformat("$_$@$%@$/"),
|
||||||
|
format='*r')
|
||||||
|
|
||||||
|
dependents = spec_dependents.get(spec)
|
||||||
|
if dependents:
|
||||||
|
print('The following packages depend on it:')
|
||||||
|
spack.cmd.display_specs(dependents, **display_args)
|
||||||
|
|
||||||
|
envs = spec_envs.get(spec)
|
||||||
|
if envs:
|
||||||
|
print('It is used by the following environments:')
|
||||||
|
colify([e.name for e in envs], indent=4)
|
||||||
|
|
||||||
|
msgs = []
|
||||||
|
if spec_dependents:
|
||||||
|
msgs.append(
|
||||||
|
'use `spack uninstall --dependents` to uninstall dependents '
|
||||||
|
'as well.')
|
||||||
|
if spec_envs:
|
||||||
|
msgs.append(
|
||||||
|
'use `spack env remove` to remove environments, or '
|
||||||
|
'`spack remove` to remove specs from environments.')
|
||||||
|
if ev.active:
|
||||||
|
msgs.append('consider using `spack remove` to remove the spec '
|
||||||
|
'from this environment')
|
||||||
|
print()
|
||||||
|
tty.die('There are still dependents.', *msgs)
|
||||||
|
|
||||||
# Process dependent_list and update uninstall_list
|
|
||||||
has_error = False
|
|
||||||
if dependent_list and not args.dependents and not args.force:
|
|
||||||
for spec, lst in dependent_list.items():
|
|
||||||
tty.error("Will not uninstall %s" % spec.cformat("$_$@$%@$/"))
|
|
||||||
print('')
|
|
||||||
print('The following packages depend on it:')
|
|
||||||
spack.cmd.display_specs(lst, **display_args)
|
|
||||||
print('')
|
|
||||||
has_error = True
|
|
||||||
elif args.dependents:
|
elif args.dependents:
|
||||||
for key, lst in dependent_list.items():
|
for spec, lst in spec_dependents.items():
|
||||||
uninstall_list.extend(lst)
|
uninstall_list.extend(lst)
|
||||||
uninstall_list = list(set(uninstall_list))
|
uninstall_list = list(set(uninstall_list))
|
||||||
if has_error:
|
|
||||||
tty.die('Use `spack uninstall --dependents` '
|
|
||||||
'to uninstall these dependencies as well.')
|
|
||||||
|
|
||||||
return uninstall_list
|
return uninstall_list
|
||||||
|
|
||||||
@ -196,5 +268,6 @@ def uninstall(parser, args):
|
|||||||
tty.die('uninstall requires at least one package argument.',
|
tty.die('uninstall requires at least one package argument.',
|
||||||
' Use `spack uninstall --all` to uninstall ALL packages.')
|
' Use `spack uninstall --all` to uninstall ALL packages.')
|
||||||
|
|
||||||
|
# [any] here handles the --all case by forcing all specs to be returned
|
||||||
uninstall_specs(
|
uninstall_specs(
|
||||||
args, spack.cmd.parse_specs(args.packages) if args.packages else [any])
|
args, spack.cmd.parse_specs(args.packages) if args.packages else [any])
|
||||||
|
@ -242,7 +242,7 @@ def config_dict(yaml_data):
|
|||||||
return yaml_data[key]
|
return yaml_data[key]
|
||||||
|
|
||||||
|
|
||||||
def list_environments():
|
def all_environment_names():
|
||||||
"""List the names of environments that currently exist."""
|
"""List the names of environments that currently exist."""
|
||||||
# just return empty if the env path does not exist. A read-only
|
# just return empty if the env path does not exist. A read-only
|
||||||
# operation like list should not try to create a directory.
|
# operation like list should not try to create a directory.
|
||||||
@ -258,6 +258,12 @@ def list_environments():
|
|||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def all_environments():
|
||||||
|
"""Generator for all named Environments."""
|
||||||
|
for name in all_environment_names():
|
||||||
|
yield read(name)
|
||||||
|
|
||||||
|
|
||||||
def validate(data, filename=None):
|
def validate(data, filename=None):
|
||||||
global _validator
|
global _validator
|
||||||
if _validator is None:
|
if _validator is None:
|
||||||
@ -362,6 +368,11 @@ def name(self):
|
|||||||
else:
|
else:
|
||||||
return self.path
|
return self.path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def active(self):
|
||||||
|
"""True if this environment is currently active."""
|
||||||
|
return active and self.path == active.path
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def manifest_path(self):
|
def manifest_path(self):
|
||||||
"""Path to spack.yaml file in this environment."""
|
"""Path to spack.yaml file in this environment."""
|
||||||
@ -480,8 +491,7 @@ def remove(self, query_spec, force=False):
|
|||||||
specs_hashes = zip(
|
specs_hashes = zip(
|
||||||
self.concretized_user_specs, self.concretized_order)
|
self.concretized_user_specs, self.concretized_order)
|
||||||
matches = [
|
matches = [
|
||||||
s for s, h in specs_hashes
|
s for s, h in specs_hashes if query_spec.dag_hash() == h]
|
||||||
if s.satisfies(query_spec) or query_spec.dag_hash() == h]
|
|
||||||
|
|
||||||
if not matches:
|
if not matches:
|
||||||
raise EnvError("Not found: {0}".format(query_spec))
|
raise EnvError("Not found: {0}".format(query_spec))
|
||||||
@ -615,12 +625,6 @@ def install_all(self, args=None):
|
|||||||
os.remove(build_log_link)
|
os.remove(build_log_link)
|
||||||
os.symlink(spec.package.build_log_path, build_log_link)
|
os.symlink(spec.package.build_log_path, build_log_link)
|
||||||
|
|
||||||
def uninstall(self, args):
|
|
||||||
"""Uninstall all the specs in an Environment."""
|
|
||||||
specs = self._get_environment_specs(recurse_dependencies=True)
|
|
||||||
args.all = False
|
|
||||||
spack.cmd.uninstall.uninstall_specs(args, specs)
|
|
||||||
|
|
||||||
def status(self, stream, **kwargs):
|
def status(self, stream, **kwargs):
|
||||||
"""List the specs in an environment."""
|
"""List the specs in an environment."""
|
||||||
tty.msg('In environment %s' % self.name)
|
tty.msg('In environment %s' % self.name)
|
||||||
@ -635,10 +639,10 @@ def status(self, stream, **kwargs):
|
|||||||
current = [(s, c) for s, c in concretized if s in self.user_specs]
|
current = [(s, c) for s, c in concretized if s in self.user_specs]
|
||||||
|
|
||||||
def write_kind(s):
|
def write_kind(s):
|
||||||
color.cwrite('@c{%s}\n' % str(s), stream)
|
color.cwrite('@c{%s}\n' % color.cescape(s), stream)
|
||||||
|
|
||||||
def write_user_spec(s, c):
|
def write_user_spec(s, c):
|
||||||
color.cwrite('@%s{----} %s\n' % (c, str(s)), stream)
|
color.cwrite('@%s{----} %s\n' % (c, color.cescape(s)), stream)
|
||||||
|
|
||||||
if added:
|
if added:
|
||||||
write_kind('added:')
|
write_kind('added:')
|
||||||
@ -661,23 +665,44 @@ def write_user_spec(s, c):
|
|||||||
write_user_spec(s, 'r')
|
write_user_spec(s, 'r')
|
||||||
stream.write(c.tree(**kwargs))
|
stream.write(c.tree(**kwargs))
|
||||||
|
|
||||||
|
def all_specs_by_hash(self):
|
||||||
|
"""Map of hashes to spec for all specs in this environment."""
|
||||||
|
hashes = {}
|
||||||
|
for h in self.concretized_order:
|
||||||
|
specs = self.specs_by_hash[h].traverse(deptype=('link', 'run'))
|
||||||
|
for spec in specs:
|
||||||
|
hashes[spec.dag_hash()] = spec
|
||||||
|
return hashes
|
||||||
|
|
||||||
|
def all_specs(self):
|
||||||
|
"""Return all specs, even those a user spec would shadow."""
|
||||||
|
return sorted(self.all_specs_by_hash().values())
|
||||||
|
|
||||||
|
def all_hashes(self):
|
||||||
|
"""Return all specs, even those a user spec would shadow."""
|
||||||
|
return list(self.all_specs_by_hash().keys())
|
||||||
|
|
||||||
def _get_environment_specs(self, recurse_dependencies=True):
|
def _get_environment_specs(self, recurse_dependencies=True):
|
||||||
"""Returns the specs of all the packages in an environment.
|
"""Returns the specs of all the packages in an environment.
|
||||||
|
|
||||||
If these specs appear under different user_specs, only one copy
|
If these specs appear under different user_specs, only one copy
|
||||||
is added to the list returned."""
|
is added to the list returned.
|
||||||
|
"""
|
||||||
package_to_spec = {}
|
package_to_spec = {}
|
||||||
spec_list = list()
|
spec_list = list()
|
||||||
|
|
||||||
for spec_hash in self.concretized_order:
|
for spec_hash in self.concretized_order:
|
||||||
spec = self.specs_by_hash[spec_hash]
|
spec = self.specs_by_hash[spec_hash]
|
||||||
|
|
||||||
specs = spec.traverse(deptype=('link', 'run')) \
|
specs = (spec.traverse(deptype=('link', 'run'))
|
||||||
if recurse_dependencies else (spec,)
|
if recurse_dependencies else (spec,))
|
||||||
|
|
||||||
for dep in specs:
|
for dep in specs:
|
||||||
if dep.name in package_to_spec:
|
prior = package_to_spec.get(dep.name)
|
||||||
tty.warn("{0} takes priority over {1}"
|
if prior and prior != dep:
|
||||||
.format(package_to_spec[dep.name].format(),
|
tty.debug("{0} takes priority over {1}"
|
||||||
dep.format()))
|
.format(package_to_spec[dep.name].format(),
|
||||||
|
dep.format()))
|
||||||
else:
|
else:
|
||||||
package_to_spec[dep.name] = dep
|
package_to_spec[dep.name] = dep
|
||||||
spec_list.append(dep)
|
spec_list.append(dep)
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
remove = SpackCommand('remove')
|
remove = SpackCommand('remove')
|
||||||
concretize = SpackCommand('concretize')
|
concretize = SpackCommand('concretize')
|
||||||
stage = SpackCommand('stage')
|
stage = SpackCommand('stage')
|
||||||
|
uninstall = SpackCommand('uninstall')
|
||||||
|
|
||||||
|
|
||||||
def test_add():
|
def test_add():
|
||||||
@ -541,9 +542,38 @@ def test_env_commands_die_with_no_env_arg():
|
|||||||
# these have an optional env arg and raise errors via tty.die
|
# these have an optional env arg and raise errors via tty.die
|
||||||
with pytest.raises(spack.main.SpackCommandError):
|
with pytest.raises(spack.main.SpackCommandError):
|
||||||
env('loads')
|
env('loads')
|
||||||
with pytest.raises(spack.main.SpackCommandError):
|
|
||||||
env('uninstall')
|
|
||||||
|
|
||||||
# This should NOT raise an error with no environment
|
# This should NOT raise an error with no environment
|
||||||
# it just tells the user there isn't an environment
|
# it just tells the user there isn't an environment
|
||||||
env('status')
|
env('status')
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_blocks_uninstall(mock_stage, mock_fetch, install_mockery):
|
||||||
|
env('create', 'test')
|
||||||
|
with ev.read('test'):
|
||||||
|
add('mpileaks')
|
||||||
|
install('--fake')
|
||||||
|
|
||||||
|
out = uninstall('mpileaks', fail_on_error=False)
|
||||||
|
assert uninstall.returncode == 1
|
||||||
|
assert 'used by the following environments' in out
|
||||||
|
|
||||||
|
|
||||||
|
def test_uninstall_removes_from_env(mock_stage, mock_fetch, install_mockery):
|
||||||
|
env('create', 'test')
|
||||||
|
with ev.read('test'):
|
||||||
|
add('mpileaks')
|
||||||
|
add('libelf')
|
||||||
|
install('--fake')
|
||||||
|
|
||||||
|
test = ev.read('test')
|
||||||
|
assert any(s.name == 'mpileaks' for s in test.specs_by_hash.values())
|
||||||
|
assert any(s.name == 'libelf' for s in test.specs_by_hash.values())
|
||||||
|
|
||||||
|
with ev.read('test'):
|
||||||
|
uninstall('-ya')
|
||||||
|
|
||||||
|
test = ev.read('test')
|
||||||
|
assert not test.specs_by_hash
|
||||||
|
assert not test.concretized_order
|
||||||
|
assert not test.user_specs
|
||||||
|
Loading…
Reference in New Issue
Block a user