BinaryPackageUniverse: Provde equivalent_packages

Signed-off-by: Niels Thykier <niels@thykier.net>
ubuntu/rebased
Niels Thykier 6 years ago
parent ef813bf0d8
commit 0eb8b5a201
No known key found for this signature in database
GPG Key ID: A65B78DBE67C7AAC

@ -308,11 +308,12 @@ class InstallabilityTesterBuilder(object):
relations, eqv_table = self._build_eqv_packages_table(package_table, reverse_package_table) relations, eqv_table = self._build_eqv_packages_table(package_table, reverse_package_table)
universe = BinaryPackageUniverse(relations, intern_set(self._essentials), intern_set(broken)) universe = BinaryPackageUniverse(relations,
intern_set(self._essentials),
intern_set(broken),
intern_set(eqv_table))
solver = InstallabilityTester(universe, solver = InstallabilityTester(universe, self._testing)
self._testing,
eqv_table)
return universe, solver return universe, solver

@ -22,7 +22,7 @@ from britney2.utils import iter_except
class InstallabilityTester(object): class InstallabilityTester(object):
def __init__(self, universe, testing, eqv_table): def __init__(self, universe, testing):
"""Create a new installability tester """Create a new installability tester
universe is a BinaryPackageUniverse universe is a BinaryPackageUniverse
@ -37,7 +37,6 @@ class InstallabilityTester(object):
self._universe = universe self._universe = universe
self._testing = testing self._testing = testing
self._eqv_table = eqv_table
self._stats = InstallabilityStats() self._stats = InstallabilityStats()
logger_name = ".".join((self.__class__.__module__, self.__class__.__name__)) logger_name = ".".join((self.__class__.__module__, self.__class__.__name__))
self.logger = logging.getLogger(logger_name) self.logger = logging.getLogger(logger_name)
@ -67,18 +66,18 @@ class InstallabilityTester(object):
in testing. in testing.
""" """
universe = self._universe
check_inst = self._check_inst check_inst = self._check_inst
cbroken = self._cache_broken cbroken = self._cache_broken
cache_inst = self._cache_inst cache_inst = self._cache_inst
eqv_table = self._eqv_table
testing = self._testing testing = self._testing
tcopy = [x for x in testing] tcopy = [x for x in testing]
for t in filterfalse(cache_inst.__contains__, tcopy): for t in filterfalse(cache_inst.__contains__, tcopy):
if t in cbroken: if t in cbroken:
continue continue
res = check_inst(t) res = check_inst(t)
if t in eqv_table: if t in universe.equivalent_packages:
eqv = (x for x in eqv_table[t] if x in testing) eqv = (x for x in universe.packages_equivalent_to(t) if x in testing)
if res: if res:
cache_inst.update(eqv) cache_inst.update(eqv)
else: else:
@ -198,7 +197,6 @@ class InstallabilityTester(object):
universe = self._universe universe = self._universe
testing = self._testing testing = self._testing
cbroken = self._cache_broken cbroken = self._cache_broken
eqv_table = self._eqv_table
# Our installability verdict - start with "yes" and change if # Our installability verdict - start with "yes" and change if
# prove otherwise. # prove otherwise.
@ -242,7 +240,7 @@ class InstallabilityTester(object):
# curry check_loop # curry check_loop
check_loop = partial(self._check_loop, universe, testing, check_loop = partial(self._check_loop, universe, testing,
eqv_table, stats, musts, never, cbroken) stats, musts, never, cbroken)
# Useful things to remember: # Useful things to remember:
# #
@ -340,7 +338,6 @@ class InstallabilityTester(object):
def resolve_choices(self, check, musts, never, choices): def resolve_choices(self, check, musts, never, choices):
universe = self._universe universe = self._universe
testing = self._testing testing = self._testing
eqv_table = self._eqv_table
stats = self._stats stats = self._stats
cbroken = self._cache_broken cbroken = self._cache_broken
@ -357,7 +354,7 @@ class InstallabilityTester(object):
check_tmp = [p] check_tmp = [p]
# _check_loop assumes that "musts" is up to date # _check_loop assumes that "musts" is up to date
musts_copy.add(p) musts_copy.add(p)
if not self._check_loop(universe, testing, eqv_table, if not self._check_loop(universe, testing,
stats, musts_copy, never_tmp, stats, musts_copy, never_tmp,
cbroken, choices_tmp, cbroken, choices_tmp,
check_tmp): check_tmp):
@ -409,7 +406,7 @@ class InstallabilityTester(object):
stats.backtrace_last_option += 1 stats.backtrace_last_option += 1
return False return False
def _check_loop(self, universe, testing, eqv_table, stats, musts, never, def _check_loop(self, universe, testing, stats, musts, never,
cbroken, choices, check, len=len, cbroken, choices, check, len=len,
frozenset=frozenset): frozenset=frozenset):
"""Finds all guaranteed dependencies via "check". """Finds all guaranteed dependencies via "check".
@ -468,7 +465,7 @@ class InstallabilityTester(object):
check.extend(candidates) check.extend(candidates)
musts.update(candidates) musts.update(candidates)
else: else:
possible_eqv = set(x for x in candidates if x in eqv_table) possible_eqv = set(x for x in candidates if x in universe.equivalent_packages)
if len(possible_eqv) > 1: if len(possible_eqv) > 1:
# Exploit equivalency to reduce the number of # Exploit equivalency to reduce the number of
# candidates if possible. Basically, this # candidates if possible. Basically, this
@ -484,7 +481,7 @@ class InstallabilityTester(object):
for chosen in iter_except(possible_eqv.pop, KeyError): for chosen in iter_except(possible_eqv.pop, KeyError):
new_cand.add(chosen) new_cand.add(chosen)
possible_eqv -= eqv_table[chosen] possible_eqv -= universe.packages_equivalent_to(chosen)
stats.eqv_table_total_number_of_alternatives_eliminated += len(candidates) - len(new_cand) stats.eqv_table_total_number_of_alternatives_eliminated += len(candidates) - len(new_cand)
if len(new_cand) == 1: if len(new_cand) == 1:
check.extend(new_cand) check.extend(new_cand)
@ -507,7 +504,6 @@ class InstallabilityTester(object):
# The minimal essential set cache is not present - # The minimal essential set cache is not present -
# compute it now. # compute it now.
testing = self._testing testing = self._testing
eqv_table = self._eqv_table
cbroken = self._cache_broken cbroken = self._cache_broken
universe = self._universe universe = self._universe
stats = self._stats stats = self._stats
@ -519,7 +515,7 @@ class InstallabilityTester(object):
not_satisfied = partial(filter, start.isdisjoint) not_satisfied = partial(filter, start.isdisjoint)
while ess_base: while ess_base:
self._check_loop(universe, testing, eqv_table, stats, self._check_loop(universe, testing, stats,
start, ess_never, cbroken, start, ess_never, cbroken,
ess_choices, ess_base) ess_choices, ess_base)
if ess_choices: if ess_choices:
@ -548,7 +544,6 @@ class InstallabilityTester(object):
def compute_stats(self): def compute_stats(self):
universe = self._universe universe = self._universe
eqv_table = self._eqv_table
graph_stats = defaultdict(ArchStats) graph_stats = defaultdict(ArchStats)
seen_eqv = defaultdict(set) seen_eqv = defaultdict(set)
@ -559,8 +554,8 @@ class InstallabilityTester(object):
arch_stats.nodes += 1 arch_stats.nodes += 1
if pkg in eqv_table and pkg not in seen_eqv[pkg_arch]: if pkg in universe.equivalent_packages and pkg not in seen_eqv[pkg_arch]:
eqv = [e for e in eqv_table[pkg] if e.architecture == pkg_arch] eqv = [e for e in universe.packages_equivalent_to(pkg) if e.architecture == pkg_arch]
arch_stats.eqv_nodes += len(eqv) arch_stats.eqv_nodes += len(eqv)
arch_stats.add_dep_edges(relations.dependencies) arch_stats.add_dep_edges(relations.dependencies)

@ -51,10 +51,11 @@ class BinaryPackageUniverse(object):
of a "minor" lie about the "broken" packages. of a "minor" lie about the "broken" packages.
""" """
def __init__(self, relations, essential_packages, broken_packages): def __init__(self, relations, essential_packages, broken_packages, equivalent_packages):
self._relations = relations self._relations = relations
self._essential_packages = essential_packages self._essential_packages = essential_packages
self._broken_packages = broken_packages self._broken_packages = broken_packages
self._equivalent_packages = equivalent_packages
def dependencies_of(self, pkg_id): def dependencies_of(self, pkg_id):
"""Returns the set of dependencies of a given package """Returns the set of dependencies of a given package
@ -141,6 +142,17 @@ class BinaryPackageUniverse(object):
""" """
return self._broken_packages return self._broken_packages
@property
def equivalent_packages(self):
"""A frozenset of all binary packages that are equivalent to at least one other package
The binary packages in this set has the property that "universe.packages_equivalent_to(pkg_id)"
will return a set of at least 2 or more elements for each of them.
:return A frozenset of BinaryPackageIds of packages that are equivalent to other packages.
"""
return self._equivalent_packages
def __contains__(self, pkg_id): def __contains__(self, pkg_id):
return pkg_id in self._relations return pkg_id in self._relations

Loading…
Cancel
Save