Rewrite the main run to use the solver and allow combined migrations

Signed-off-by: Niels Thykier <niels@thykier.net>
master
Niels Thykier 12 years ago
parent 65f74c226d
commit 326cc0d98b

@ -2233,7 +2233,7 @@ class Britney(object):
if len(actions) == 1:
item = actions[0]
# apply the changes
affected, undo = self.doop_source(item, lundo)
affected, undo = self.doop_source(item, hint_undo=lundo)
undo_list = [(undo, item)]
if item.architecture == 'source':
affected_architectures = set(self.options.architectures)
@ -2256,6 +2256,7 @@ class Britney(object):
for item in actions:
item_affected, undo = self.doop_source(item,
hint_undo=lundo,
removals=removals)
affected.update(item_affected)
undo_list.append((undo, item))
@ -2301,82 +2302,66 @@ class Britney(object):
final result is successful, otherwise (None, None).
"""
extra = []
deferred = []
skipped = []
mark_passed = False
position = len(packages)
groups = set()
for y in sorted((y for y in packages), key=attrgetter('uvname')):
updates, rms, _ = self._compute_groups(y.package, y.suite, y.architecture, y.is_removal)
groups.add((y, frozenset(updates), frozenset(rms)))
if selected is None:
selected = []
if nuninst:
nuninst_comp = nuninst
nuninst_orig = nuninst
else:
nuninst_comp = self.nuninst_orig
# local copies for better performance
dependencies = self.dependencies
nuninst_orig = self.nuninst_orig
nuninst_last_accepted = nuninst_orig
maybe_reschuled = []
worklist = self._inst_tester.solve_groups(groups)
worklist.reverse()
self.output_write("recur: [] %s %d/%d\n" % (",".join(x.uvname for x in selected), len(packages), len(extra)))
# loop on the packages (or better, actions)
while packages:
item = packages.pop(0)
# this is the marker for the first loop
if not mark_passed and position < 0:
mark_passed = True
packages.extend(deferred)
del deferred
else: position -= 1
# defer packages if their dependency has been already skipped
if not mark_passed:
defer = False
for p in dependencies.get(item, []):
if p in skipped:
deferred.append(item)
skipped.append(item)
defer = True
break
if defer: continue
self.output_write("trying: %s\n" % (item.uvname))
(better, nuninst, undo_list, arch) = self.try_migration([item], nuninst_comp, lundo=lundo)
# check if the action improved the uninstallability counters
if better:
while worklist:
comp = worklist.pop()
comp_name = ' '.join(item.uvname for item in comp)
self.output_write("trying: %s\n" % comp_name)
accepted, nuninst_after, comp_undo, failed_arch = self.try_migration(comp, nuninst_last_accepted, lundo)
if accepted:
nuninst_last_accepted = nuninst_after
selected.extend(comp)
if lundo is not None:
lundo.extend(undo_list)
selected.append(item)
packages.extend(extra)
extra = []
self.output_write("accepted: %s\n" % (item.uvname))
self.output_write(" ori: %s\n" % (self.eval_nuninst(self.nuninst_orig)))
self.output_write(" pre: %s\n" % (self.eval_nuninst(nuninst_comp)))
self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst, nuninst_comp)))
lundo.extend(comp_undo)
self.output_write("accepted: %s\n" % comp_name)
self.output_write(" ori: %s\n" % (self.eval_nuninst(nuninst_orig)))
self.output_write(" pre: %s\n" % (self.eval_nuninst(nuninst_last_accepted)))
self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst_after)))
if len(selected) <= 20:
self.output_write(" all: %s\n" % (" ".join(x.uvname for x in selected)))
else:
self.output_write(" most: (%d) .. %s\n" % (len(selected), " ".join(x.uvname for x in selected[-20:])))
nuninst_comp = nuninst
else:
broken = sorted(b for b in nuninst_after[failed_arch]
if b not in nuninst_last_accepted[failed_arch])
compare_nuninst = None
if any(item for item in comp if item.architecture != 'source'):
compare_nuninst = nuninst_last_accepted
# 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]))))
extra.append(item)
if not mark_passed:
skipped.append(item)
self.output_write("skipped: %s (%d, %d)\n" % (comp_name, len(maybe_reschuled), len(worklist)))
self.output_write(" got: %s\n" % (self.eval_nuninst(nuninst_after, compare_nuninst)))
self.output_write(" * %s: %s\n" % (failed_arch, ", ".join(broken)))
if len(comp) > 1:
self.output_write(" - splitting the component into single items and retrying them\n")
worklist.extend([item] for item in comp)
else:
extra.extend(comp)
self.output_write(" finish: [%s]\n" % ",".join( x.uvname for x in selected ))
self.output_write("endloop: %s\n" % (self.eval_nuninst(self.nuninst_orig)))
self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst_comp)))
self.output_write(" now: %s\n" % (self.eval_nuninst(nuninst_last_accepted)))
self.output_write(eval_uninst(self.options.architectures,
newly_uninst(self.nuninst_orig, nuninst_comp)))
newly_uninst(self.nuninst_orig, nuninst_last_accepted)))
self.output_write("\n")
return (nuninst_comp, extra)
return (nuninst_last_accepted, extra)
def do_all(self, hinttype=None, init=None, actions=None):
@ -2807,7 +2792,6 @@ class Britney(object):
self.upgrade_me = [ make_migrationitem(x, self.sources) for x in upgrade_me ]
self.upgrade_me.extend(make_migrationitem(x, self.sources) for x in removals)
def auto_hinter(self):
"""Auto-generate "easy" hints.
@ -2824,7 +2808,7 @@ class Britney(object):
excuses relationships. If they build a circular dependency, which we already
know as not-working with the standard do_all algorithm, try to `easy` them.
"""
self.__log("> Processing hints from the auto hinter [Partial-ordering]",
self.__log("> Processing hints from the auto hinter",
type="I")
# consider only excuses which are valid candidates
@ -2833,28 +2817,6 @@ class Britney(object):
excuses_deps = dict((name, set(excuse.deps)) for name, excuse in excuses.items())
sources_t = self.sources['testing']
groups = set()
for y in sorted((y for y in self.upgrade_me if y.uvname in excuses), key=attrgetter('uvname')):
if y.is_removal and y.package not in sources_t:
# Already removed
continue
if not y.is_removal:
excuse = excuses[y.uvname]
if y.architecture == 'source' and y.uvname in sources_t and sources_t[y.uvname][VERSION] == excuse.ver[1]:
# Already migrated
continue
adds, rms, _ = self._compute_groups(y.package, y.suite,
y.architecture, y.is_removal,
include_hijacked=True)
groups.add((y, frozenset(adds), frozenset(rms)))
for comp in self._inst_tester.solve_groups(groups):
if len(comp) > 1:
self.do_hint("easy", "autohinter", comp)
self.__log("> Processing hints from the auto hinter [Original]",
type="I")
def find_related(e, hint, circular_first=False):
if e not in excuses:
return False

Loading…
Cancel
Save