diff --git a/britney.py b/britney.py index cbaadfe..41b8329 100755 --- a/britney.py +++ b/britney.py @@ -2264,6 +2264,55 @@ class Britney(object): return nuninst + def try_migration(self, actions, nuninst_now, lundo=None, automatic_revert=True): + is_accepted = True + affected_architectures = set() + item = actions + packages_t = self.binaries['testing'] + + nobreakall_arches = self.options.nobreakall_arches + new_arches = self.options.new_arches + break_arches = self.options.break_arches + arch = None + + # apply the changes + affected, undo = self.doop_source(item, lundo) + single_undo = (undo, item) + + # Copy nuninst_comp - we have to deep clone affected + # architectures. + + # NB: We do this *after* updating testing as we have to filter out + # removed binaries. Otherwise, uninstallable binaries that were + # removed by the item would still be counted. + if item.architecture == 'source': + affected_architectures = set(self.options.architectures) + else: + affected_architectures.add(item.architecture) + nuninst_after = clone_nuninst(nuninst_now, packages_t, affected_architectures) + + # check the affected packages on all the architectures + for arch in affected_architectures: + check_archall = arch in nobreakall_arches + + self._check_packages(packages_t, arch, affected, check_archall, nuninst_after) + + # if the uninstallability counter is worse than before, break the loop + if automatic_revert and len(nuninst_after[arch]) > len(nuninst_now[arch]): + # ... except for a few special cases + if (item.architecture != 'source' and arch not in new_arches) or \ + (arch not in break_arches): + is_accepted = False + break + + # check if the action improved the uninstallability counters + if not is_accepted and automatic_revert: + undo_list = [single_undo] + undo_changes(undo_list, self._inst_tester, self.sources, self.binaries) + + return (is_accepted, nuninst_after, single_undo, arch) + + def iter_packages(self, packages, selected, nuninst=None, lundo=None): """Iter on the list of actions and apply them one-by-one @@ -2285,14 +2334,7 @@ class Britney(object): nuninst_comp = self.nuninst_orig # local copies for better performance - binaries = self.binaries['testing'] - sources = self.sources - architectures = self.options.architectures - nobreakall_arches = self.options.nobreakall_arches - new_arches = self.options.new_arches - break_arches = self.options.break_arches dependencies = self.dependencies - check_packages = partial(self._check_packages, binaries) self.output_write("recur: [] %s %d/%d\n" % (",".join(x.uvname for x in selected), len(packages), len(extra))) @@ -2320,41 +2362,12 @@ class Britney(object): self.output_write("trying: %s\n" % (item.uvname)) - better = True - - # apply the changes - affected, undo = self.doop_source(item, lundo) - - # Copy nuninst_comp - we have to deep clone affected - # architectures. - - # NB: We do this *after* updating testing as we have to filter out - # removed binaries. Otherwise, uninstallable binaries that were - # removed by the item would still be counted. - if item.architecture == 'source': - affected_architectures = architectures - else: - affected_architectures = [item.architecture] - nuninst = clone_nuninst(nuninst_comp, binaries, affected_architectures) - - - # check the affected packages on all the architectures - for arch in affected_architectures: - check_archall = arch in nobreakall_arches - - check_packages(arch, affected, check_archall, nuninst) - - # if the uninstallability counter is worse than before, break the loop - if ((item.architecture != 'source' and arch not in new_arches) or \ - (arch not in break_arches)) and len(nuninst[arch]) > len(nuninst_comp[arch]): - better = False - break - + (better, nuninst, undo_item, arch) = self.try_migration(item, nuninst_comp, lundo=lundo) # check if the action improved the uninstallability counters if better: if lundo is not None: - lundo.append((undo, item)) + lundo.append(undo_item) selected.append(item) packages.extend(extra) extra = [] @@ -2368,6 +2381,7 @@ class Britney(object): self.output_write(" most: (%d) .. %s\n" % (len(selected), " ".join(x.uvname for x in selected[-20:]))) nuninst_comp = nuninst else: + # NB: try_migration already reverted this for us, so just print the results and move on self.output_write("skipped: %s (%d <- %d)\n" % (item.uvname, len(extra), len(packages))) self.output_write(" got: %s\n" % (self.eval_nuninst(nuninst, item.architecture != 'source' and nuninst_comp or None))) self.output_write(" * %s: %s\n" % (arch, ", ".join(sorted(b for b in nuninst[arch] if b not in nuninst_comp[arch])))) @@ -2375,9 +2389,6 @@ class Britney(object): extra.append(item) if not mark_passed: skipped.append(item) - single_undo = [(undo, item)] - # (local-scope) binaries is actually self.binaries["testing"] so we cannot use it here. - undo_changes(single_undo, self._inst_tester, sources, self.binaries) self.output_write(" finish: [%s]\n" % ",".join( x.uvname for x in selected ))