spack dependencies: support --deptype argument

- `spack dependencies` can now take a --deptype argument to only traverse
  particular deptypes

- add a new "common" argument for deptype in spack.cmd.common.arguments

- Database.installed_relatives() can now also take a deptype argument
  - this is used by `spack dependencies --installed`
This commit is contained in:
Todd Gamblin 2019-04-20 22:41:14 -07:00
parent 3dac78fc19
commit 2e22fc1090
4 changed files with 48 additions and 11 deletions

View File

@ -9,6 +9,7 @@
import spack.cmd
import spack.config
import spack.dependency as dep
import spack.environment as ev
import spack.modules
import spack.spec
@ -104,6 +105,19 @@ def default(self, value):
pass
class DeptypeAction(argparse.Action):
"""Creates a tuple of valid dependency tpyes from a deptype argument."""
def __call__(self, parser, namespace, values, option_string=None):
deptype = dep.all_deptypes
if values:
deptype = tuple(x.strip() for x in values.split(','))
if deptype == ('all',):
deptype = 'all'
deptype = dep.canonical_deptype(deptype)
setattr(namespace, self.dest, deptype)
_arguments['constraint'] = Args(
'constraint', nargs=argparse.REMAINDER, action=ConstraintAction,
help='constraint to select a subset of installed packages')
@ -128,6 +142,11 @@ def default(self, value):
dest='dirty',
help='unset harmful variables in the build environment (default)')
_arguments['deptype'] = Args(
'--deptype', action=DeptypeAction, default=dep.all_deptypes,
help="comma-separated list of deptypes to traverse\ndefault=%s"
% ','.join(dep.all_deptypes))
_arguments['dirty'] = Args(
'--dirty',
action='store_true',

View File

@ -8,10 +8,11 @@
import llnl.util.tty as tty
from llnl.util.tty.colify import colify
import spack.environment as ev
import spack.store
import spack.repo
import spack.cmd
import spack.cmd.common.arguments as arguments
import spack.environment as ev
import spack.repo
import spack.store
description = "show dependencies of a package"
section = "basic"
@ -26,6 +27,7 @@ def setup_parser(subparser):
subparser.add_argument(
'-t', '--transitive', action='store_true', default=False,
help="show all transitive dependencies")
arguments.add_common_arguments(subparser, ['deptype'])
subparser.add_argument(
'-V', '--no-expand-virtuals', action='store_false', default=True,
dest="expand_virtuals", help="do not expand virtual dependencies")
@ -45,7 +47,7 @@ def dependencies(parser, args):
format_string = '{name}{@version}{%compiler}{/hash:7}'
tty.msg("Dependencies of %s" % spec.format(format_string, color=True))
deps = spack.store.db.installed_relatives(
spec, 'children', args.transitive)
spec, 'children', args.transitive, deptype=args.deptype)
if deps:
spack.cmd.display_specs(deps, long=True)
else:
@ -63,9 +65,9 @@ def dependencies(parser, args):
dependencies = set()
for pkg in packages:
dependencies.update(
set(pkg.possible_dependencies(
args.transitive, args.expand_virtuals)))
possible = pkg.possible_dependencies(
args.transitive, args.expand_virtuals, deptype=args.deptype)
dependencies.update(possible)
if spec.name in dependencies:
dependencies.remove(spec.name)

View File

@ -875,7 +875,8 @@ def remove(self, spec):
return self._remove(spec)
@_autospec
def installed_relatives(self, spec, direction='children', transitive=True):
def installed_relatives(self, spec, direction='children', transitive=True,
deptype='all'):
"""Return installed specs related to this one."""
if direction not in ('parents', 'children'):
raise ValueError("Invalid direction: %s" % direction)
@ -883,11 +884,12 @@ def installed_relatives(self, spec, direction='children', transitive=True):
relatives = set()
for spec in self.query(spec):
if transitive:
to_add = spec.traverse(direction=direction, root=False)
to_add = spec.traverse(
direction=direction, root=False, deptype=deptype)
elif direction == 'parents':
to_add = spec.dependents()
to_add = spec.dependents(deptype=deptype)
else: # direction == 'children'
to_add = spec.dependencies()
to_add = spec.dependencies(deptype=deptype)
for relative in to_add:
hash_key = relative.dag_hash()

View File

@ -32,6 +32,20 @@ def test_transitive_dependencies(mock_packages):
assert expected == actual
def test_transitive_dependencies_with_deptypes(mock_packages):
out = dependencies('--transitive', '--deptype=link,run', 'dtbuild1')
deps = set(re.split(r'\s+', out.strip()))
assert set(['dtlink2', 'dtrun2']) == deps
out = dependencies('--transitive', '--deptype=build', 'dtbuild1')
deps = set(re.split(r'\s+', out.strip()))
assert set(['dtbuild2', 'dtlink2']) == deps
out = dependencies('--transitive', '--deptype=link', 'dtbuild1')
deps = set(re.split(r'\s+', out.strip()))
assert set(['dtlink2']) == deps
@pytest.mark.db
def test_immediate_installed_dependencies(mock_packages, database):
with color_when(False):