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
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