Coverage for britney2/installability/universe.py: 100%

38 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2024-04-18 20:48 +0000

1# -*- coding: utf-8 -*- 

2 

3# Copyright (C) 2012 Niels Thykier <niels@thykier.net> 

4 

5# This program is free software; you can redistribute it and/or modify 

6# it under the terms of the GNU General Public License as published by 

7# the Free Software Foundation; either version 2 of the License, or 

8# (at your option) any later version. 

9 

10# This program is distributed in the hope that it will be useful, 

11# but WITHOUT ANY WARRANTY; without even the implied warranty of 

12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

13# GNU General Public License for more details. 

14 

15 

16class BinaryPackageRelation(object): 

17 """All relations of a given binary package""" 

18 

19 __slots__ = ['pkg_ids', 'dependencies', 'negative_dependencies', 'reverse_dependencies'] 

20 

21 def __init__(self, pkg_ids, dependencies, negative_dependencies, reverse_dependencies): 

22 self.pkg_ids = pkg_ids 

23 self.dependencies = dependencies 

24 self.negative_dependencies = negative_dependencies 

25 self.reverse_dependencies = reverse_dependencies 

26 

27 

28class BinaryPackageUniverse(object): 

29 """A "universe" of all binary packages and their relations 

30 

31 The package universe is a read-only ("immutable") data structure 

32 that knows of all binary packages and their internal relations. 

33 The relations are either in Conjunctive Normal Form (CNF) represented 

34 via sets of sets of the package ids or simply sets of package ids. 

35 

36 Being immutable, the universe does *not* track stateful data such 

37 as "which package is in what suite?" nor "is this package installable 

38 in that suite?". 

39 

40 The universe also includes some packages that are considered "broken". 

41 These packages have been identified to always be uninstallability 

42 regardless of the selection of package available (e.g. the depend 

43 on a non-existent package or has a relation that is impossible to 

44 satisfy). 

45 

46 For these packages, the universe only tracks that they 

47 exist and that they are broken. This implies that their relations 

48 have been nulled into empty sets and they have been removed from 

49 the relations of other packages. This optimizes analysis of the 

50 universe on packages that is/can be installable at the expense 

51 of a "minor" lie about the "broken" packages. 

52 """ 

53 

54 def __init__(self, relations, essential_packages, broken_packages, equivalent_packages): 

55 self._relations = relations 

56 self._essential_packages = essential_packages 

57 self._broken_packages = broken_packages 

58 self._equivalent_packages = equivalent_packages 

59 

60 def dependencies_of(self, pkg_id): 

61 """Returns the set of dependencies of a given package 

62 

63 :param pkg_id: The BinaryPackageId of a binary package. 

64 :return: A set containing the package ids all of the dependencies 

65 of the input package in CNF. 

66 """ 

67 return self._relations[pkg_id].dependencies 

68 

69 def negative_dependencies_of(self, pkg_id): 

70 """Returns the set of negative dependencies of a given package 

71 

72 Note that there is no "reverse_negative_dependencies_of" method, 

73 since negative dependencies have no "direction" unlike positive 

74 dependencies. 

75 

76 :param pkg_id: The BinaryPackageId of a binary package. 

77 :return: A set containing the package ids all of the negative 

78 dependencies of the input package. 

79 """ 

80 return self._relations[pkg_id].negative_dependencies 

81 

82 def reverse_dependencies_of(self, pkg_id): 

83 """Returns the set of reverse dependencies of a given package 

84 

85 Note that a package is considered a reverse dependency of the 

86 given package as long as at least one of its dependency relations 

87 *could* be satisfied by the given package. 

88 

89 :param pkg_id: The BinaryPackageId of a binary package. 

90 :return: A set containing the package ids all of the reverse 

91 dependencies of the input package. 

92 """ 

93 return self._relations[pkg_id].reverse_dependencies 

94 

95 def are_equivalent(self, pkg_id1, pkg_id2): 

96 """Test if pkg_id1 and pkg_id2 are equivalent 

97 

98 :param pkg_id1 The id of the first package 

99 :param pkg_id2 The id of the second package 

100 :return: True if pkg_id1 and pkg_id2 have the same "signature" in 

101 the package dependency graph (i.e. relations can not tell 

102 them apart semantically except for their name). Otherwise False. 

103 

104 Note that this can return True even if pkg_id1 and pkg_id2 can 

105 tell each other apart. 

106 """ 

107 return pkg_id2 in self.packages_equivalent_to(pkg_id1) 

108 

109 def packages_equivalent_to(self, pkg_id): 

110 """Determine which packages are equivalent to a given package 

111 

112 :param pkg_id: The BinaryPackageId of a binary package. 

113 :return: A frozenset of all package ids that are equivalent to the 

114 input package. 

115 """ 

116 return self._relations[pkg_id].pkg_ids 

117 

118 def relations_of(self, pkg_id): 

119 """Get the direct relations of a given package 

120 

121 :param pkg_id: The BinaryPackageId of a binary package. 

122 :return: A BinaryPackageRelation describing all known direct 

123 relations for the package. 

124 """ 

125 return self._relations[pkg_id] 

126 

127 @property 

128 def essential_packages(self): 

129 """A frozenset of all "Essential: yes" binaries in the universe 

130 

131 :return A frozenset of BinaryPackageIds of all binaries that are 

132 marked as essential. 

133 """ 

134 return self._essential_packages 

135 

136 @property 

137 def broken_packages(self): 

138 """A frozenset of all broken binaries in the universe 

139 

140 :return A frozenset of BinaryPackageIds of all binaries that are 

141 considered "broken" and had their relations nulled. 

142 """ 

143 return self._broken_packages 

144 

145 @property 

146 def equivalent_packages(self): 

147 """A frozenset of all binary packages that are equivalent to at least one other package 

148 

149 The binary packages in this set has the property that "universe.packages_equivalent_to(pkg_id)" 

150 will return a set of at least 2 or more elements for each of them. 

151 

152 :return A frozenset of BinaryPackageIds of packages that are equivalent to other packages. 

153 """ 

154 return self._equivalent_packages 

155 

156 def __contains__(self, pkg_id): 

157 return pkg_id in self._relations 

158 

159 def __iter__(self): 

160 yield from self._relations