1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
# Copyright 2013-2021 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)
"""Infrastructure used by tests for mocking packages and repos."""
import collections
import spack.provider_index
import spack.util.naming
from spack.dependency import Dependency
from spack.spec import Spec
from spack.version import Version
__all__ = ["MockPackageMultiRepo"]
class MockPackageBase(object):
"""Internal base class for mocking ``spack.package.PackageBase``.
Use ``MockPackageMultiRepo.add_package()`` to create new instances.
"""
virtual = False
def __init__(self, dependencies, dependency_types,
conditions=None, versions=None):
"""Instantiate a new MockPackageBase.
This is not for general use; it needs to be constructed by a
``MockPackageMultiRepo``, as we need to know about *all* packages
to find possible depenencies.
"""
self.spec = None
self._installed_upstream = False
def provides(self, vname):
return vname in self.provided
@property
def virtuals_provided(self):
return [v.name for v, c in self.provided]
@classmethod
def possible_dependencies(
cls, transitive=True, deptype='all', visited=None, virtuals=None):
visited = {} if visited is None else visited
for name, conditions in cls.dependencies.items():
# check whether this dependency could be of the type asked for
types = [dep.type for cond, dep in conditions.items()]
types = set.union(*types)
if not any(d in types for d in deptype):
continue
visited.setdefault(cls.name, set())
for dep_name in cls.dependencies:
if dep_name in visited:
continue
visited.setdefault(dep_name, set())
if not transitive:
continue
cls._repo.get(dep_name).possible_dependencies(
transitive, deptype, visited, virtuals)
return visited
def content_hash(self):
# Unlike real packages, MockPackage doesn't have a corresponding
# package.py file; in that sense, the content_hash is always the same.
return self.__class__.__name__
class MockPackageMultiRepo(object):
"""Mock package repository, mimicking ``spack.repo.Repo``."""
def __init__(self):
self.spec_to_pkg = {}
self.namespace = 'mock' # repo namespace
self.full_namespace = 'spack.pkg.mock' # python import namespace
def get(self, spec):
if not isinstance(spec, spack.spec.Spec):
spec = Spec(spec)
if spec.name not in self.spec_to_pkg:
raise spack.repo.UnknownPackageError(spec.fullname)
return self.spec_to_pkg[spec.name]
def get_pkg_class(self, name):
namespace, _, name = name.rpartition(".")
if namespace and namespace != self.namespace:
raise spack.repo.InvalidNamespaceError(
"bad namespace: %s" % self.namespace)
return self.spec_to_pkg[name]
def exists(self, name):
return name in self.spec_to_pkg
def is_virtual(self, name, use_index=True):
return False
def repo_for_pkg(self, name):
import collections
Repo = collections.namedtuple('Repo', ['namespace'])
return Repo('mockrepo')
def __contains__(self, item):
return item in self.spec_to_pkg
def add_package(self, name, dependencies=None, dependency_types=None,
conditions=None):
"""Factory method for creating mock packages.
This creates a new subclass of ``MockPackageBase``, ensures that its
``name`` and ``__name__`` properties are set up correctly, and
returns a new instance.
We use a factory function here because many functions and properties
of packages need to be class functions.
Args:
name (str): name of the new package
dependencies (list): list of mock packages to be dependencies
for this new package (optional; no deps if not provided)
dependency_type (list): list of deptypes for each dependency
(optional; will be default_deptype if not provided)
conditions (list): condition specs for each dependency (optional)
"""
if not dependencies:
dependencies = []
if not dependency_types:
dependency_types = [
spack.dependency.default_deptype] * len(dependencies)
assert len(dependencies) == len(dependency_types)
# new class for the mock package
class MockPackage(MockPackageBase):
pass
MockPackage.__name__ = spack.util.naming.mod_to_class(name)
MockPackage.name = name
MockPackage._repo = self
# set up dependencies
MockPackage.dependencies = collections.OrderedDict()
for dep, dtype in zip(dependencies, dependency_types):
d = Dependency(MockPackage, Spec(dep.name), type=dtype)
if not conditions or dep.name not in conditions:
MockPackage.dependencies[dep.name] = {Spec(name): d}
else:
dep_conditions = conditions[dep.name]
dep_conditions = dict(
(Spec(x), Dependency(MockPackage, Spec(y), type=dtype))
for x, y in dep_conditions.items())
MockPackage.dependencies[dep.name] = dep_conditions
# each package has some fake versions
versions = list(Version(x) for x in [1, 2, 3])
MockPackage.versions = dict(
(x, {'preferred': False}) for x in versions
)
MockPackage.variants = {}
MockPackage.provided = {}
MockPackage.conflicts = {}
MockPackage.patches = {}
mock_package = MockPackage(
dependencies, dependency_types, conditions, versions)
self.spec_to_pkg[name] = mock_package
self.spec_to_pkg["mockrepo." + name] = mock_package
return mock_package
@property
def provider_index(self):
return spack.provider_index.ProviderIndex()
|