track whether a package was installed "explicitly"

Adds a new attribute in the database to track whether a package was
installed explicitly or not, where explicitly is the user running `spack
install <package>` and implicitly is it being installed as a dependency.
It also adds arguments to `spack find` to find these packages such that
it should be possible to query the packages that were installed
implicitly and are not currently depended upon any longer.
This commit is contained in:
Tom Scogland 2016-04-29 10:21:55 -07:00
parent 53df9fbb4f
commit 4acdfeae61
4 changed files with 31 additions and 12 deletions

View File

@ -57,6 +57,12 @@ def setup_parser(subparser):
'-L', '--very-long', action='store_true',
help='Show dependency hashes as well as versions.')
subparser.add_argument(
'-e', '--explicit', action='store_true',
help='Show only specs that were installed explicitly')
subparser.add_argument(
'-E', '--implicit', action='store_true',
help='Show only specs that were installed as dependencies')
subparser.add_argument(
'-u', '--unknown', action='store_true',
help='Show only specs Spack does not have a package for.')
@ -163,7 +169,14 @@ def find(parser, args):
installed = any
if args.unknown:
known = False
q_args = { 'installed' : installed, 'known' : known }
explicit = None
if args.explicit:
explicit = False
if args.implicit:
explicit = True
q_args = { 'installed' : installed, 'known' : known, "explicit" : explicit }
# Get all the specs the user asked for
if not query_specs:

View File

@ -78,4 +78,5 @@ def install(parser, args):
ignore_deps=args.ignore_deps,
make_jobs=args.jobs,
verbose=args.verbose,
fake=args.fake)
fake=args.fake,
explicit=True)

View File

@ -92,22 +92,24 @@ class InstallRecord(object):
dependents left.
"""
def __init__(self, spec, path, installed, ref_count=0):
def __init__(self, spec, path, installed, ref_count=0, explicit=False):
self.spec = spec
self.path = str(path)
self.installed = bool(installed)
self.ref_count = ref_count
self.explicit = explicit
def to_dict(self):
return { 'spec' : self.spec.to_node_dict(),
'path' : self.path,
'installed' : self.installed,
'ref_count' : self.ref_count }
'ref_count' : self.ref_count,
'explicit' : self.explicit }
@classmethod
def from_dict(cls, spec, dictionary):
d = dictionary
return InstallRecord(spec, d['path'], d['installed'], d['ref_count'])
return InstallRecord(spec, d['path'], d['installed'], d['ref_count'], d.get('explicit', False))
class Database(object):
@ -370,7 +372,7 @@ def _read(self):
self.reindex(spack.install_layout)
def _add(self, spec, path, directory_layout=None):
def _add(self, spec, path, directory_layout=None, explicit=False):
"""Add an install record for spec at path to the database.
This assumes that the spec is not already installed. It
@ -392,7 +394,7 @@ def _add(self, spec, path, directory_layout=None):
rec.path = path
else:
self._data[key] = InstallRecord(spec, path, True)
self._data[key] = InstallRecord(spec, path, True, explicit=explicit)
for dep in spec.dependencies.values():
self._increment_ref_count(dep, directory_layout)
@ -415,7 +417,7 @@ def _increment_ref_count(self, spec, directory_layout=None):
self._data[key].ref_count += 1
@_autospec
def add(self, spec, path):
def add(self, spec, path, explicit=False):
"""Add spec at path to database, locking and reading DB to sync.
``add()`` will lock and read from the DB on disk.
@ -424,7 +426,7 @@ def add(self, spec, path):
# TODO: ensure that spec is concrete?
# Entire add is transactional.
with self.write_transaction():
self._add(spec, path)
self._add(spec, path, explicit=explicit)
def _get_matching_spec_key(self, spec, **kwargs):
@ -513,7 +515,7 @@ def installed_extensions_for(self, extendee_spec):
# TODO: conditional way to do this instead of catching exceptions
def query(self, query_spec=any, known=any, installed=True):
def query(self, query_spec=any, known=any, installed=True, explicit=any):
"""Run a query on the database.
``query_spec``
@ -553,6 +555,8 @@ def query(self, query_spec=any, known=any, installed=True):
for key, rec in self._data.items():
if installed is not any and rec.installed != installed:
continue
if explicit is not any and rec.explicit != explicit:
continue
if known is not any and spack.repo.exists(rec.spec.name) != known:
continue
if query_spec is any or rec.spec.satisfies(query_spec):

View File

@ -857,7 +857,8 @@ def do_install(self,
skip_patch=False,
verbose=False,
make_jobs=None,
fake=False):
fake=False,
explicit=False):
"""Called by commands to install a package and its dependencies.
Package implementations should override install() to describe
@ -995,7 +996,7 @@ def build_process():
# note: PARENT of the build process adds the new package to
# the database, so that we don't need to re-read from file.
spack.installed_db.add(self.spec, self.prefix)
spack.installed_db.add(self.spec, self.prefix, explicit=explicit)
def sanity_check_prefix(self):
"""This function checks whether install succeeded."""