|
|
|
@ -328,11 +328,11 @@ class InstallabilityTester(object):
|
|
|
|
|
#
|
|
|
|
|
# * A package is installable if never and musts are disjointed
|
|
|
|
|
# and both check and choices are empty.
|
|
|
|
|
# - exception: _pick_choice may determine the installability
|
|
|
|
|
# - exception: resolve_choice may determine the installability
|
|
|
|
|
# of t via recursion (calls _check_inst). In this case
|
|
|
|
|
# check and choices are not (always) empty.
|
|
|
|
|
|
|
|
|
|
def _pick_choice(rebuild, set=set, len=len):
|
|
|
|
|
def _prune_choices(rebuild, set=set, len=len):
|
|
|
|
|
"""Picks a choice from choices and updates rebuild.
|
|
|
|
|
|
|
|
|
|
Prunes the choices and updates "rebuild" to reflect the
|
|
|
|
@ -382,15 +382,55 @@ class InstallabilityTester(object):
|
|
|
|
|
# all alternatives would violate the conflicts or are uninstallable
|
|
|
|
|
# => package is not installable
|
|
|
|
|
stats.choice_presolved += 1
|
|
|
|
|
return None
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# The choice is still deferred
|
|
|
|
|
rebuild.add(frozenset(remain))
|
|
|
|
|
|
|
|
|
|
if check or not rebuild:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# END _prune_choices
|
|
|
|
|
|
|
|
|
|
while check:
|
|
|
|
|
if not check_loop(choices, check):
|
|
|
|
|
verdict = False
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if choices:
|
|
|
|
|
rebuild = set()
|
|
|
|
|
|
|
|
|
|
if not _prune_choices(rebuild):
|
|
|
|
|
verdict = False
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
while not check and rebuild:
|
|
|
|
|
# We have to "guess" now, which is always fun, but not cheap. We
|
|
|
|
|
# stop guessing:
|
|
|
|
|
# - once we run out of choices to make (obviously), OR
|
|
|
|
|
# - if one of the choices exhaust all but one option
|
|
|
|
|
if self.resolve_choice(check, musts, never, rebuild):
|
|
|
|
|
# The recursive call have already updated the
|
|
|
|
|
# cache so there is not point in doing it again.
|
|
|
|
|
return True
|
|
|
|
|
choices = rebuild
|
|
|
|
|
|
|
|
|
|
if verdict:
|
|
|
|
|
# if t is installable, then so are all packages in musts
|
|
|
|
|
self._cache_inst.update(musts)
|
|
|
|
|
stats.solved_installable += 1
|
|
|
|
|
else:
|
|
|
|
|
stats.solved_uninstallable += 1
|
|
|
|
|
|
|
|
|
|
return verdict
|
|
|
|
|
|
|
|
|
|
choice = iter(rebuild.pop())
|
|
|
|
|
def resolve_choice(self, check, musts, never, choices):
|
|
|
|
|
universe = self._universe
|
|
|
|
|
testing = self._testing
|
|
|
|
|
eqv_table = self._eqv_table
|
|
|
|
|
stats = self._stats
|
|
|
|
|
cbroken = self._cache_broken
|
|
|
|
|
|
|
|
|
|
choice = iter(choices.pop())
|
|
|
|
|
last = next(choice) # pick one to go last
|
|
|
|
|
for p in choice:
|
|
|
|
|
musts_copy = musts.copy()
|
|
|
|
@ -406,7 +446,7 @@ class InstallabilityTester(object):
|
|
|
|
|
|
|
|
|
|
# Test if we can pick p without any consequences.
|
|
|
|
|
# - when we can, we avoid a backtrack point.
|
|
|
|
|
if never_tmp <= never and choices_tmp <= rebuild:
|
|
|
|
|
if never_tmp <= never and choices_tmp <= choices:
|
|
|
|
|
# we can pick p without picking up new conflicts
|
|
|
|
|
# or unresolved choices. Therefore we commit to
|
|
|
|
|
# using p.
|
|
|
|
@ -427,7 +467,7 @@ class InstallabilityTester(object):
|
|
|
|
|
# We are not sure that p is safe, setup a backtrack
|
|
|
|
|
# point and recurse.
|
|
|
|
|
never_tmp |= never
|
|
|
|
|
choices_tmp |= rebuild
|
|
|
|
|
choices_tmp |= choices
|
|
|
|
|
if self._check_inst(p, musts_copy, never_tmp,
|
|
|
|
|
choices_tmp):
|
|
|
|
|
# Success, p was a valid choice and made it all
|
|
|
|
@ -450,34 +490,6 @@ class InstallabilityTester(object):
|
|
|
|
|
musts.add(last)
|
|
|
|
|
stats.backtrace_last_option += 1
|
|
|
|
|
return False
|
|
|
|
|
# END _pick_choice
|
|
|
|
|
|
|
|
|
|
while check:
|
|
|
|
|
if not check_loop(choices, check):
|
|
|
|
|
verdict = False
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if choices:
|
|
|
|
|
rebuild = set()
|
|
|
|
|
# We have to "guess" now, which is always fun, but not cheap
|
|
|
|
|
r = _pick_choice(rebuild)
|
|
|
|
|
if r is None:
|
|
|
|
|
verdict = False
|
|
|
|
|
break
|
|
|
|
|
if r:
|
|
|
|
|
# The recursive call have already updated the
|
|
|
|
|
# cache so there is not point in doing it again.
|
|
|
|
|
return True
|
|
|
|
|
choices = rebuild
|
|
|
|
|
|
|
|
|
|
if verdict:
|
|
|
|
|
# if t is installable, then so are all packages in musts
|
|
|
|
|
self._cache_inst.update(musts)
|
|
|
|
|
stats.solved_installable += 1
|
|
|
|
|
else:
|
|
|
|
|
stats.solved_uninstallable += 1
|
|
|
|
|
|
|
|
|
|
return verdict
|
|
|
|
|
|
|
|
|
|
def _check_loop(self, universe, testing, eqv_table, stats, musts, never,
|
|
|
|
|
cbroken, choices, check, len=len,
|
|
|
|
|