find and uninstall work when installed package is no longer in spack.

- Make switching between git branches easier.
- Make future removal of packages easier.
This commit is contained in:
Todd Gamblin 2014-08-04 07:40:53 -07:00
parent 2f21ca64e0
commit d0b179962b
4 changed files with 54 additions and 14 deletions

View File

@ -28,6 +28,7 @@
import spack
import spack.cmd
import spack.packages
description="Remove an installed package"
@ -68,7 +69,15 @@ def uninstall(parser, args):
if len(matching_specs) == 0:
tty.die("%s does not match any installed packages." % spec)
pkgs.extend(spack.db.get(s) for s in matching_specs)
for s in matching_specs:
try:
# should work if package is known to spack
pkgs.append(spack.db.get(s))
except spack.packages.UnknownPackageError, 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

View File

@ -155,7 +155,8 @@ def read_spec(self, path):
"""Read the contents of a file and parse them as a spec"""
with closing(open(path)) as spec_file:
string = spec_file.read().replace('\n', '')
return Spec(string)
# Specs from files are assumed normal and concrete
return Spec(string, concrete=True)
def make_path_for_spec(self, spec):

View File

@ -322,9 +322,6 @@ class SomePackage(Package):
def __init__(self, spec):
# These attributes are required for all packages.
attr_required(self.__class__, 'homepage')
# this determines how the package should be built.
self.spec = spec
@ -396,9 +393,13 @@ def stage(self):
raise ValueError("Can only get a stage for a concrete package.")
if self._stage is None:
if not self.url:
raise PackageVersionError(self.version)
# TODO: move this logic into a mirror module.
mirror_path = "%s/%s" % (self.name, "%s-%s.%s" % (
self.name, self.version, extension(self.url)))
self._stage = Stage(
self.url, mirror_path=mirror_path, name=self.spec.short_spec)
return self._stage
@ -531,8 +532,6 @@ def nearest_url(version):
break
if self.versions[v].url:
url = self.versions[v].url
if not url:
raise PackageVersionError(v)
return url
if version in self.versions:

View File

@ -345,6 +345,17 @@ def __init__(self, spec_like, *dep_like, **kwargs):
self.compiler = other.compiler
self.dependencies = other.dependencies
# Specs are by default not assumed to be normal, but in some
# cases we've read them from a file want to assume normal.
# This allows us to manipulate specs that Spack doesn't have
# package.py files for.
self._normal = kwargs.get('normal', False)
self._concrete = kwargs.get('concrete', False)
# Specs cannot be concrete and non-normal.
if self._concrete:
self._normal = True
# This allows users to construct a spec DAG with literals.
# Note that given two specs a and b, Spec(a) copies a, but
# Spec(a, b) will copy a but just add b as a dep.
@ -432,11 +443,15 @@ def concrete(self):
If any of the name, version, architecture, compiler, or depdenencies
are ambiguous,then it is not concrete.
"""
return bool(not self.virtual
and self.versions.concrete
and self.architecture
and self.compiler and self.compiler.concrete
and self.dependencies.concrete)
if self._concrete:
return True
self._concrete = bool(not self.virtual
and self.versions.concrete
and self.architecture
and self.compiler and self.compiler.concrete
and self.dependencies.concrete)
return self._concrete
def preorder_traversal(self, visited=None, d=0, **kwargs):
@ -606,7 +621,7 @@ def _expand_virtual_packages(self):
# If there are duplicate providers or duplicate provider deps, this
# consolidates them and merges constraints.
self.normalize()
self.normalize(force=True)
def concretize(self):
@ -621,9 +636,13 @@ def concretize(self):
with requirements of its pacakges. See flatten() and normalize() for
more details on this.
"""
if self._concrete:
return
self.normalize()
self._expand_virtual_packages()
self._concretize_helper()
self._concrete = True
def concretized(self):
@ -754,7 +773,7 @@ def _normalize_helper(self, visited, spec_deps, provider_index):
dependency._normalize_helper(visited, spec_deps, provider_index)
def normalize(self):
def normalize(self, **kwargs):
"""When specs are parsed, any dependencies specified are hanging off
the root, and ONLY the ones that were explicitly provided are there.
Normalization turns a partial flat spec into a DAG, where:
@ -772,6 +791,9 @@ def normalize(self):
TODO: normalize should probably implement some form of cycle detection,
to ensure that the spec is actually a DAG.
"""
if self._normal and not kwargs.get('force', False):
return
# Ensure first that all packages & compilers in the DAG exist.
self.validate_names()
@ -805,6 +827,9 @@ def normalize(self):
raise InvalidDependencyException(
self.name + " does not depend on " + comma_or(extra))
# Mark the spec as normal once done.
self._normal = True
def normalized(self):
"""Return a normalized copy of this spec without modifying this spec."""
@ -1009,6 +1034,9 @@ def _dup(self, other, **kwargs):
else:
self.dependencies = DependencyMap()
self._normal = other._normal
self._concrete = other._concrete
def copy(self, **kwargs):
"""Return a copy of this spec.
@ -1261,6 +1289,9 @@ def spec(self):
spec.dependents = DependencyMap()
spec.dependencies = DependencyMap()
spec._normal = False
spec._concrete = False
# record this so that we know whether version is
# unspecified or not.
added_version = False