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', '-L', '--very-long', action='store_true',
help='Show dependency hashes as well as versions.') 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( subparser.add_argument(
'-u', '--unknown', action='store_true', '-u', '--unknown', action='store_true',
help='Show only specs Spack does not have a package for.') help='Show only specs Spack does not have a package for.')
@ -163,7 +169,14 @@ def find(parser, args):
installed = any installed = any
if args.unknown: if args.unknown:
known = False 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 # Get all the specs the user asked for
if not query_specs: if not query_specs:

View File

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

View File

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

View File

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