diff --git a/britney2/installability/builder.py b/britney2/installability/builder.py index e094d4a..73ee3d6 100644 --- a/britney2/installability/builder.py +++ b/britney2/installability/builder.py @@ -308,11 +308,10 @@ class InstallabilityTesterBuilder(object): relations, eqv_table = self._build_eqv_packages_table(package_table, reverse_package_table) - universe = BinaryPackageUniverse(relations, intern_set(self._essentials)) + universe = BinaryPackageUniverse(relations, intern_set(self._essentials), intern_set(broken)) solver = InstallabilityTester(universe, self._testing, - self._broken, eqv_table) return universe, solver diff --git a/britney2/installability/tester.py b/britney2/installability/tester.py index 3c2d29b..b14b764 100644 --- a/britney2/installability/tester.py +++ b/britney2/installability/tester.py @@ -22,7 +22,7 @@ from britney2.utils import iter_except class InstallabilityTester(object): - def __init__(self, universe, testing, broken, eqv_table): + def __init__(self, universe, testing, eqv_table): """Create a new installability tester universe is a BinaryPackageUniverse @@ -30,9 +30,6 @@ class InstallabilityTester(object): testing is a (mutable) set of package ids that determines which of the packages in universe are currently in testing. - broken is a (mutable) set of package ids that are known to - be uninstallable. - Package id: (pkg_name, pkg_version, pkg_arch) - NB: arch:all packages are "re-mapped" to given architecture. (simplifies caches and dependency checking) @@ -40,7 +37,6 @@ class InstallabilityTester(object): self._universe = universe self._testing = testing - self._broken = broken self._eqv_table = eqv_table self._stats = InstallabilityStats() logger_name = ".".join((self.__class__.__module__, self.__class__.__name__)) @@ -122,7 +118,7 @@ class InstallabilityTester(object): if pkg_id not in self._universe: # pragma: no cover raise KeyError(str(pkg_id)) - if pkg_id in self._broken: + if pkg_id in self._universe.broken_packages: self._testing.add(pkg_id) elif pkg_id not in self._testing: self._testing.add(pkg_id) @@ -162,7 +158,7 @@ class InstallabilityTester(object): if not self._universe.reverse_dependencies_of(pkg_id): # no reverse relations - safe return True - if pkg_id not in self._broken and pkg_id in self._cache_inst: + if pkg_id not in self._universe.broken_packages and pkg_id in self._cache_inst: # It is in our cache (and not guaranteed to be broken) - throw out the cache self._cache_inst = set() self._stats.cache_drops += 1 @@ -185,7 +181,7 @@ class InstallabilityTester(object): if pkg_id not in self._universe: # pragma: no cover raise KeyError(str(pkg_id)) - if pkg_id not in self._testing or pkg_id in self._broken: + if pkg_id not in self._testing or pkg_id in self._universe.broken_packages: self._stats.cache_hits += 1 return False diff --git a/britney2/installability/universe.py b/britney2/installability/universe.py index 8f08b76..ceeb465 100644 --- a/britney2/installability/universe.py +++ b/britney2/installability/universe.py @@ -36,11 +36,25 @@ class BinaryPackageUniverse(object): Being immutable, the universe does *not* track stateful data such as "which package is in what suite?" nor "is this package installable in that suite?". + + The universe also includes some packages that are considered "broken". + These packages have been identified to always be uninstallability + regardless of the selection of package available (e.g. the depend + on a non-existent package or has a relation that is impossible to + satisfy). + + For these packages, the universe only tracks that they + exist and that they are broken. This implies that their relations + have been nulled into empty sets and they have been removed from + the relations of other packages. This optimizes analysis of the + universe on packages that is/can be installable at the expense + of a "minor" lie about the "broken" packages. """ - def __init__(self, relations, essential_packages): + def __init__(self, relations, essential_packages, broken_packages): self._relations = relations self._essential_packages = essential_packages + self._broken_packages = broken_packages def dependencies_of(self, pkg_id): """Returns the set of dependencies of a given package @@ -96,8 +110,7 @@ class BinaryPackageUniverse(object): :param pkg_id: The BinaryPackageId of a binary package. :return: A frozenset of all package ids that are equivalent to the - input package. Note that this set always includes the input - package assuming it is a known package. + input package. """ return self._relations[pkg_id].pkg_ids @@ -119,6 +132,15 @@ class BinaryPackageUniverse(object): """ return self._essential_packages + @property + def broken_packages(self): + """A frozenset of all broken binaries in the universe + + :return A frozenset of BinaryPackageIds of all binaries that are + considered "broken" and had their relations nulled. + """ + return self._broken_packages + def __contains__(self, pkg_id): return pkg_id in self._relations