mirror of
				https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
				synced 2025-11-04 10:34:05 +00:00 
			
		
		
		
	inst-tester: split _pick_choice into two
Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
		
							parent
							
								
									176fe04c98
								
							
						
					
					
						commit
						97663ebaab
					
				@ -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,75 +382,14 @@ 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
 | 
			
		||||
 | 
			
		||||
            choice = iter(rebuild.pop())
 | 
			
		||||
            last = next(choice) # pick one to go last
 | 
			
		||||
            for p in choice:
 | 
			
		||||
                musts_copy = musts.copy()
 | 
			
		||||
                never_tmp = set()
 | 
			
		||||
                choices_tmp = set()
 | 
			
		||||
                check_tmp = set([p])
 | 
			
		||||
                if not self._check_loop(universe, testing, eqv_table,
 | 
			
		||||
                                        stats, musts_copy, never_tmp,
 | 
			
		||||
                                        cbroken, choices_tmp,
 | 
			
		||||
                                        check_tmp):
 | 
			
		||||
                    # p cannot be chosen/is broken (unlikely, but ...)
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
                # 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:
 | 
			
		||||
                    # we can pick p without picking up new conflicts
 | 
			
		||||
                    # or unresolved choices.  Therefore we commit to
 | 
			
		||||
                    # using p.
 | 
			
		||||
                    #
 | 
			
		||||
                    # NB: Optimally, we would go to the start of this
 | 
			
		||||
                    # routine, but to conserve stack-space, we return
 | 
			
		||||
                    # and expect to be called again later.
 | 
			
		||||
                    musts.update(musts_copy)
 | 
			
		||||
                    stats.choice_resolved_without_restore_point += 1
 | 
			
		||||
                    return False
 | 
			
		||||
 | 
			
		||||
                if not musts.isdisjoint(never_tmp):
 | 
			
		||||
                    # If we pick p, we will definitely end up making
 | 
			
		||||
                    # t uninstallable, so p is a no-go.
 | 
			
		||||
                    continue
 | 
			
		||||
 | 
			
		||||
                stats.backtrace_restore_point_created += 1
 | 
			
		||||
                # We are not sure that p is safe, setup a backtrack
 | 
			
		||||
                # point and recurse.
 | 
			
		||||
                never_tmp |= never
 | 
			
		||||
                choices_tmp |= rebuild
 | 
			
		||||
                if self._check_inst(p, musts_copy, never_tmp,
 | 
			
		||||
                                    choices_tmp):
 | 
			
		||||
                    # Success, p was a valid choice and made it all
 | 
			
		||||
                    # installable
 | 
			
		||||
                    return True
 | 
			
		||||
 | 
			
		||||
                # If we get here, we failed to find something that
 | 
			
		||||
                # would satisfy choice (without breaking the
 | 
			
		||||
                # installability of t).  This means p cannot be used
 | 
			
		||||
                # to satisfy the dependencies, so pretend to conflict
 | 
			
		||||
                # with it - hopefully it will reduce future choices.
 | 
			
		||||
                never.add(p)
 | 
			
		||||
                stats.backtrace_restore_point_used += 1
 | 
			
		||||
 | 
			
		||||
            # Optimization for the last case; avoid the recursive call
 | 
			
		||||
            # and just assume the last will lead to a solution.  If it
 | 
			
		||||
            # doesn't there is no solution and if it does, we don't
 | 
			
		||||
            # have to back-track anyway.
 | 
			
		||||
            check.add(last)
 | 
			
		||||
            musts.add(last)
 | 
			
		||||
            stats.backtrace_last_option += 1
 | 
			
		||||
            return False
 | 
			
		||||
        # END _pick_choice
 | 
			
		||||
        # END _prune_choices
 | 
			
		||||
 | 
			
		||||
        while check:
 | 
			
		||||
            if not check_loop(choices, check):
 | 
			
		||||
@ -459,15 +398,20 @@ class InstallabilityTester(object):
 | 
			
		||||
 | 
			
		||||
            if choices:
 | 
			
		||||
                rebuild = set()
 | 
			
		||||
                # We have to "guess" now, which is always fun, but not cheap
 | 
			
		||||
                r = _pick_choice(rebuild)
 | 
			
		||||
                if r is None:
 | 
			
		||||
 | 
			
		||||
                if not _prune_choices(rebuild):
 | 
			
		||||
                    verdict = False
 | 
			
		||||
                    break
 | 
			
		||||
                if r:
 | 
			
		||||
                    # The recursive call have already updated the
 | 
			
		||||
                    # cache so there is not point in doing it again.
 | 
			
		||||
                    return True
 | 
			
		||||
 | 
			
		||||
                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:
 | 
			
		||||
@ -479,6 +423,74 @@ class InstallabilityTester(object):
 | 
			
		||||
 | 
			
		||||
        return verdict
 | 
			
		||||
 | 
			
		||||
    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()
 | 
			
		||||
            never_tmp = set()
 | 
			
		||||
            choices_tmp = set()
 | 
			
		||||
            check_tmp = set([p])
 | 
			
		||||
            if not self._check_loop(universe, testing, eqv_table,
 | 
			
		||||
                                    stats, musts_copy, never_tmp,
 | 
			
		||||
                                    cbroken, choices_tmp,
 | 
			
		||||
                                    check_tmp):
 | 
			
		||||
                # p cannot be chosen/is broken (unlikely, but ...)
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            # Test if we can pick p without any consequences.
 | 
			
		||||
            # - when we can, we avoid a backtrack point.
 | 
			
		||||
            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.
 | 
			
		||||
                #
 | 
			
		||||
                # NB: Optimally, we would go to the start of this
 | 
			
		||||
                # routine, but to conserve stack-space, we return
 | 
			
		||||
                # and expect to be called again later.
 | 
			
		||||
                musts.update(musts_copy)
 | 
			
		||||
                stats.choice_resolved_without_restore_point += 1
 | 
			
		||||
                return False
 | 
			
		||||
 | 
			
		||||
            if not musts.isdisjoint(never_tmp):
 | 
			
		||||
                # If we pick p, we will definitely end up making
 | 
			
		||||
                # t uninstallable, so p is a no-go.
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            stats.backtrace_restore_point_created += 1
 | 
			
		||||
            # We are not sure that p is safe, setup a backtrack
 | 
			
		||||
            # point and recurse.
 | 
			
		||||
            never_tmp |= never
 | 
			
		||||
            choices_tmp |= choices
 | 
			
		||||
            if self._check_inst(p, musts_copy, never_tmp,
 | 
			
		||||
                                choices_tmp):
 | 
			
		||||
                # Success, p was a valid choice and made it all
 | 
			
		||||
                # installable
 | 
			
		||||
                return True
 | 
			
		||||
 | 
			
		||||
            # If we get here, we failed to find something that
 | 
			
		||||
            # would satisfy choice (without breaking the
 | 
			
		||||
            # installability of t).  This means p cannot be used
 | 
			
		||||
            # to satisfy the dependencies, so pretend to conflict
 | 
			
		||||
            # with it - hopefully it will reduce future choices.
 | 
			
		||||
            never.add(p)
 | 
			
		||||
            stats.backtrace_restore_point_used += 1
 | 
			
		||||
 | 
			
		||||
        # Optimization for the last case; avoid the recursive call
 | 
			
		||||
        # and just assume the last will lead to a solution.  If it
 | 
			
		||||
        # doesn't there is no solution and if it does, we don't
 | 
			
		||||
        # have to back-track anyway.
 | 
			
		||||
        check.add(last)
 | 
			
		||||
        musts.add(last)
 | 
			
		||||
        stats.backtrace_last_option += 1
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def _check_loop(self, universe, testing, eqv_table, stats, musts, never,
 | 
			
		||||
                    cbroken, choices, check, len=len,
 | 
			
		||||
                    frozenset=frozenset):
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user