From 2e22fc10902ba85f76033b11070e3e2f755a5e0a Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 20 Apr 2019 22:41:14 -0700 Subject: 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` --- lib/spack/spack/cmd/common/arguments.py | 19 +++++++++++++++++++ lib/spack/spack/cmd/dependencies.py | 14 ++++++++------ lib/spack/spack/database.py | 10 ++++++---- lib/spack/spack/test/cmd/dependencies.py | 14 ++++++++++++++ 4 files changed, 47 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/common/arguments.py b/lib/spack/spack/cmd/common/arguments.py index 1428b8da36..8a38d09f03 100644 --- a/lib/spack/spack/cmd/common/arguments.py +++ b/lib/spack/spack/cmd/common/arguments.py @@ -9,6 +9,7 @@ import multiprocessing 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 @@ class SetParallelJobs(argparse.Action): 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 @@ _arguments['clean'] = Args( 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', diff --git a/lib/spack/spack/cmd/dependencies.py b/lib/spack/spack/cmd/dependencies.py index 31817783b2..671224edb4 100644 --- a/lib/spack/spack/cmd/dependencies.py +++ b/lib/spack/spack/cmd/dependencies.py @@ -8,10 +8,11 @@ import argparse import llnl.util.tty as tty from llnl.util.tty.colify import colify +import spack.cmd +import spack.cmd.common.arguments as arguments import spack.environment as ev -import spack.store import spack.repo -import spack.cmd +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) diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py index 9781a7ed75..b7adae18fb 100644 --- a/lib/spack/spack/database.py +++ b/lib/spack/spack/database.py @@ -875,7 +875,8 @@ class Database(object): 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 @@ class Database(object): 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() diff --git a/lib/spack/spack/test/cmd/dependencies.py b/lib/spack/spack/test/cmd/dependencies.py index b86b158b47..d38591e907 100644 --- a/lib/spack/spack/test/cmd/dependencies.py +++ b/lib/spack/spack/test/cmd/dependencies.py @@ -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): -- cgit v1.2.3-60-g2f50