possible_dependencies() now reports missing dependencies
- Add an optional argument so that `possible_dependencies()` will report missing dependencies. - Add a test to ensure it works. - Ignore missing dependencies in `possible_dependencies()` by default.
This commit is contained in:
parent
81b147cc0a
commit
531f370e0d
@ -556,16 +556,19 @@ def installed_upstream(self):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def possible_dependencies(
|
def possible_dependencies(
|
||||||
cls, transitive=True, expand_virtuals=True, deptype='all',
|
cls, transitive=True, expand_virtuals=True, deptype='all',
|
||||||
visited=None):
|
visited=None, missing=None):
|
||||||
"""Return dict of possible dependencies of this package.
|
"""Return dict of possible dependencies of this package.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
transitive (bool): return all transitive dependencies if True,
|
transitive (bool, optional): return all transitive dependencies if
|
||||||
only direct dependencies if False.
|
True, only direct dependencies if False (default True)..
|
||||||
expand_virtuals (bool): expand virtual dependencies into all
|
expand_virtuals (bool, optional): expand virtual dependencies into
|
||||||
possible implementations.
|
all possible implementations (default True)
|
||||||
deptype (str or tuple): dependency types to consider
|
deptype (str or tuple, optional): dependency types to consider
|
||||||
visited (set): set of names of dependencies visited so far.
|
visited (dicct, optional): dict of names of dependencies visited so
|
||||||
|
far, mapped to their immediate dependencies' names.
|
||||||
|
missing (dict, optional): dict to populate with packages and their
|
||||||
|
*missing* dependencies.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(dict): dictionary mapping dependency names to *their*
|
(dict): dictionary mapping dependency names to *their*
|
||||||
@ -576,7 +579,12 @@ def possible_dependencies(
|
|||||||
*immediate* dependencies. If ``expand_virtuals`` is ``False``,
|
*immediate* dependencies. If ``expand_virtuals`` is ``False``,
|
||||||
virtual package names wil be inserted as keys mapped to empty
|
virtual package names wil be inserted as keys mapped to empty
|
||||||
sets of dependencies. Virtuals, if not expanded, are treated as
|
sets of dependencies. Virtuals, if not expanded, are treated as
|
||||||
though they have no immediate dependencies
|
though they have no immediate dependencies.
|
||||||
|
|
||||||
|
Missing dependencies by default are ignored, but if a
|
||||||
|
missing dict is provided, it will be populated with package names
|
||||||
|
mapped to any dependencies they have that are in no
|
||||||
|
repositories. This is only populated if transitive is True.
|
||||||
|
|
||||||
Note: the returned dict *includes* the package itself.
|
Note: the returned dict *includes* the package itself.
|
||||||
|
|
||||||
@ -586,6 +594,9 @@ def possible_dependencies(
|
|||||||
if visited is None:
|
if visited is None:
|
||||||
visited = {cls.name: set()}
|
visited = {cls.name: set()}
|
||||||
|
|
||||||
|
if missing is None:
|
||||||
|
missing = {cls.name: set()}
|
||||||
|
|
||||||
for name, conditions in cls.dependencies.items():
|
for name, conditions in cls.dependencies.items():
|
||||||
# check whether this dependency could be of the type asked for
|
# check whether this dependency could be of the type asked for
|
||||||
types = [dep.type for cond, dep in conditions.items()]
|
types = [dep.type for cond, dep in conditions.items()]
|
||||||
@ -609,12 +620,24 @@ def possible_dependencies(
|
|||||||
|
|
||||||
# recursively traverse dependencies
|
# recursively traverse dependencies
|
||||||
for dep_name in dep_names:
|
for dep_name in dep_names:
|
||||||
if dep_name not in visited:
|
if dep_name in visited:
|
||||||
visited.setdefault(dep_name, set())
|
continue
|
||||||
if transitive:
|
|
||||||
dep_cls = spack.repo.path.get_pkg_class(dep_name)
|
visited.setdefault(dep_name, set())
|
||||||
dep_cls.possible_dependencies(
|
|
||||||
transitive, expand_virtuals, deptype, visited)
|
# skip the rest if not transitive
|
||||||
|
if not transitive:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
dep_cls = spack.repo.path.get_pkg_class(dep_name)
|
||||||
|
except spack.repo.UnknownPackageError:
|
||||||
|
# log unknown packages
|
||||||
|
missing.setdefault(cls.name, set()).add(dep_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
dep_cls.possible_dependencies(
|
||||||
|
transitive, expand_virtuals, deptype, visited, missing)
|
||||||
|
|
||||||
return visited
|
return visited
|
||||||
|
|
||||||
@ -2671,6 +2694,7 @@ def possible_dependencies(*pkg_or_spec, **kwargs):
|
|||||||
transitive = kwargs.get('transitive', True)
|
transitive = kwargs.get('transitive', True)
|
||||||
expand_virtuals = kwargs.get('expand_virtuals', True)
|
expand_virtuals = kwargs.get('expand_virtuals', True)
|
||||||
deptype = kwargs.get('deptype', 'all')
|
deptype = kwargs.get('deptype', 'all')
|
||||||
|
missing = kwargs.get('missing')
|
||||||
|
|
||||||
packages = []
|
packages = []
|
||||||
for pos in pkg_or_spec:
|
for pos in pkg_or_spec:
|
||||||
@ -2686,7 +2710,7 @@ def possible_dependencies(*pkg_or_spec, **kwargs):
|
|||||||
visited = {}
|
visited = {}
|
||||||
for pkg in packages:
|
for pkg in packages:
|
||||||
pkg.possible_dependencies(
|
pkg.possible_dependencies(
|
||||||
transitive, expand_virtuals, deptype, visited)
|
transitive, expand_virtuals, deptype, visited, missing)
|
||||||
|
|
||||||
return visited
|
return visited
|
||||||
|
|
||||||
|
@ -47,6 +47,15 @@ def test_possible_dependencies(mock_packages, mpileaks_possible_deps):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_possible_dependencies_missing(mock_packages):
|
||||||
|
md = spack.repo.get("missing-dependency")
|
||||||
|
missing = {}
|
||||||
|
md.possible_dependencies(transitive=True, missing=missing)
|
||||||
|
assert missing["missing-dependency"] == set([
|
||||||
|
"this-is-a-missing-dependency"
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
def test_possible_dependencies_with_deptypes(mock_packages):
|
def test_possible_dependencies_with_deptypes(mock_packages):
|
||||||
dtbuild1 = spack.repo.get('dtbuild1')
|
dtbuild1 = spack.repo.get('dtbuild1')
|
||||||
|
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
# Copyright 2013-2019 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)
|
||||||
|
|
||||||
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
|
class MissingDependency(Package):
|
||||||
|
"""Package with a dependency that does not exist."""
|
||||||
|
|
||||||
|
homepage = "http://www.example.com"
|
||||||
|
url = "http://www.example.com/missing-dependency-1.0.tar.gz"
|
||||||
|
|
||||||
|
version('1.0', '0123456789abcdef0123456789abcdef')
|
||||||
|
|
||||||
|
# intentionally missing to test possible_dependencies()
|
||||||
|
depends_on("this-is-a-missing-dependency")
|
||||||
|
|
||||||
|
# this one is a "real" mock dependency
|
||||||
|
depends_on("a")
|
Loading…
Reference in New Issue
Block a user