Source code for spack.cmd.dependents

# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import collections
import sys

import llnl.util.tty as tty
from llnl.util.tty.colify import colify

import spack.cmd
import spack.environment as ev
import spack.repo
import spack.store
from spack.cmd.common import arguments

description = "show packages that depend on another"
section = "basic"
level = "long"


[docs] def setup_parser(subparser): subparser.add_argument( "-i", "--installed", action="store_true", default=False, help="list installed dependents of an installed spec " "instead of possible dependents of a package", ) subparser.add_argument( "-t", "--transitive", action="store_true", default=False, help="show all transitive dependents", ) arguments.add_common_arguments(subparser, ["spec"])
[docs] def inverted_dependencies(): """Iterate through all packages and return a dictionary mapping package names to possible dependencies. Virtual packages are included as sources, so that you can query dependents of, e.g., `mpi`, but virtuals are not included as actual dependents. """ dag = {} for pkg_cls in spack.repo.PATH.all_package_classes(): dag.setdefault(pkg_cls.name, set()) for dep in pkg_cls.dependencies_by_name(): deps = [dep] # expand virtuals if necessary if spack.repo.PATH.is_virtual(dep): deps += [s.name for s in spack.repo.PATH.providers_for(dep)] dag = collections.defaultdict(set) for pkg_cls in spack.repo.PATH.all_package_classes(): for _, deps_by_name in pkg_cls.dependencies.items(): for dep in deps_by_name: deps = [dep] # expand virtuals if necessary if spack.repo.PATH.is_virtual(dep): deps += [s.name for s in spack.repo.PATH.providers_for(dep)] for d in deps: dag[d].add(pkg_cls.name) return dag
[docs] def get_dependents(pkg_name, ideps, transitive=False, dependents=None): """Get all dependents for a package. Args: pkg_name (str): name of the package whose dependents should be returned ideps (dict): dictionary of dependents, from inverted_dependencies() transitive (bool or None): return transitive dependents when True """ if dependents is None: dependents = set() if pkg_name in dependents: return set() dependents.add(pkg_name) direct = ideps[pkg_name] if transitive: for dep_name in direct: get_dependents(dep_name, ideps, transitive, dependents) dependents.update(direct) return dependents
[docs] def dependents(parser, args): specs = spack.cmd.parse_specs(args.spec) if len(specs) != 1: tty.die("spack dependents takes only one spec.") if args.installed: env = ev.active_environment() spec = spack.cmd.disambiguate_spec(specs[0], env) format_string = "{name}{@version}{%compiler}{/hash:7}" if sys.stdout.isatty(): tty.msg("Dependents of %s" % spec.cformat(format_string)) deps = spack.store.STORE.db.installed_relatives(spec, "parents", args.transitive) if deps: spack.cmd.display_specs(deps, long=True) else: print("No dependents") else: spec = specs[0] ideps = inverted_dependencies() dependents = get_dependents(spec.name, ideps, args.transitive) dependents.remove(spec.name) if dependents: colify(sorted(dependents)) else: print("No dependents")