mirror of
https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
synced 2025-05-13 11:31:38 +00:00
britney.py: Split iter_packages into two
Extract a specialised iter_packages_hint from iter_packages that only deals with applying hints. This simplifies iter_packages AND avoids having to re-compute the uninstallability counters after each single item in the hint. This means that a hint can now avoid triggering expontential runtime provided only that the "post-hint" stage does not trigger expontential runtime. Previously the hint had to be ordered such that none of the items in the hint caused such behaviour (if at all possible). Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
parent
c25e7f9cd7
commit
a46dd88709
93
britney.py
93
britney.py
@ -2103,7 +2103,51 @@ class Britney(object):
|
|||||||
self._installability_test(p, version, arch, broken, to_check, nuninst_arch)
|
self._installability_test(p, version, arch, broken, to_check, nuninst_arch)
|
||||||
|
|
||||||
|
|
||||||
def iter_packages(self, packages, selected, hint=False, nuninst=None, lundo=None):
|
def iter_packages_hint(self, hinted_packages, lundo=None):
|
||||||
|
"""Iter on hinted list of actions and apply them in one go
|
||||||
|
|
||||||
|
This method applies the changes from "hinted_packages" to
|
||||||
|
testing and computes the uninstallability counters after te
|
||||||
|
actions are performed.
|
||||||
|
|
||||||
|
The method returns the new uninstallability counters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
removals = set()
|
||||||
|
all_affected = set()
|
||||||
|
nobreakall_arches = self.options.nobreakall_arches.split()
|
||||||
|
binaries_t = self.binaries['testing']
|
||||||
|
check_packages = partial(self._check_packages, binaries_t)
|
||||||
|
# Deep copy nuninst (in case the hint is undone)
|
||||||
|
nuninst = {k:v.copy() for k,v in self.nuninst_orig.iteritems()}
|
||||||
|
|
||||||
|
|
||||||
|
for item in hinted_packages:
|
||||||
|
_, rms, _ = self._compute_groups(item.package, item.suite,
|
||||||
|
item.architecture,
|
||||||
|
item.is_removal,
|
||||||
|
allow_smooth_updates=False)
|
||||||
|
removals.update(rms)
|
||||||
|
|
||||||
|
for item in hinted_packages:
|
||||||
|
_, affected, undo = self.doop_source(item,
|
||||||
|
removals=removals)
|
||||||
|
all_affected.update(affected)
|
||||||
|
if lundo is not None:
|
||||||
|
lundo.append((undo,item))
|
||||||
|
|
||||||
|
for arch in self.options.architectures:
|
||||||
|
if arch not in nobreakall_arches:
|
||||||
|
skip_archall = True
|
||||||
|
else:
|
||||||
|
skip_archall = False
|
||||||
|
|
||||||
|
check_packages(arch, all_affected, skip_archall, nuninst)
|
||||||
|
|
||||||
|
return nuninst
|
||||||
|
|
||||||
|
|
||||||
|
def iter_packages(self, packages, selected, nuninst=None, lundo=None):
|
||||||
"""Iter on the list of actions and apply them one-by-one
|
"""Iter on the list of actions and apply them one-by-one
|
||||||
|
|
||||||
This method applies the changes from `packages` to testing, checking the uninstallability
|
This method applies the changes from `packages` to testing, checking the uninstallability
|
||||||
@ -2132,24 +2176,9 @@ class Britney(object):
|
|||||||
dependencies = self.dependencies
|
dependencies = self.dependencies
|
||||||
check_packages = partial(self._check_packages, binaries)
|
check_packages = partial(self._check_packages, binaries)
|
||||||
|
|
||||||
# pre-process a hint batch
|
|
||||||
pre_process = {}
|
|
||||||
if selected and hint:
|
|
||||||
removals = set()
|
|
||||||
for item in selected:
|
|
||||||
_, rms, _ = self._compute_groups(item.package, item.suite,
|
|
||||||
item.architecture,
|
|
||||||
item.is_removal,
|
|
||||||
allow_smooth_updates=False)
|
|
||||||
removals.update(rms)
|
|
||||||
for package in selected:
|
|
||||||
pkg, affected, undo = self.doop_source(package,
|
|
||||||
removals=removals)
|
|
||||||
pre_process[package] = (pkg, affected, undo)
|
|
||||||
|
|
||||||
if lundo is None:
|
if lundo is None:
|
||||||
lundo = []
|
lundo = []
|
||||||
if not hint:
|
|
||||||
self.output_write("recur: [%s] %s %d/%d\n" % ("", ",".join(x.uvname for x in selected), len(packages), len(extra)))
|
self.output_write("recur: [%s] %s %d/%d\n" % ("", ",".join(x.uvname for x in selected), len(packages), len(extra)))
|
||||||
|
|
||||||
# loop on the packages (or better, actions)
|
# loop on the packages (or better, actions)
|
||||||
@ -2174,45 +2203,32 @@ class Britney(object):
|
|||||||
break
|
break
|
||||||
if defer: continue
|
if defer: continue
|
||||||
|
|
||||||
if not hint:
|
|
||||||
self.output_write("trying: %s\n" % (pkg.uvname))
|
self.output_write("trying: %s\n" % (pkg.uvname))
|
||||||
|
|
||||||
better = True
|
better = True
|
||||||
nuninst = {}
|
nuninst = {}
|
||||||
|
|
||||||
# apply the changes
|
# apply the changes
|
||||||
if pkg in pre_process:
|
|
||||||
item, affected, undo = pre_process[pkg]
|
|
||||||
else:
|
|
||||||
item, affected, undo = self.doop_source(pkg, lundo)
|
item, affected, undo = self.doop_source(pkg, lundo)
|
||||||
if hint:
|
|
||||||
lundo.append((undo, item))
|
|
||||||
|
|
||||||
# check the affected packages on all the architectures
|
# check the affected packages on all the architectures
|
||||||
for arch in (item.architecture == 'source' and architectures or (item.architecture,)):
|
for arch in (item.architecture == 'source' and architectures or (item.architecture,)):
|
||||||
if arch not in nobreakall_arches:
|
if arch not in nobreakall_arches:
|
||||||
skip_archall = True
|
skip_archall = True
|
||||||
else: skip_archall = False
|
else:
|
||||||
|
skip_archall = False
|
||||||
|
|
||||||
nuninst[arch] = set(x for x in nuninst_comp[arch] if x in binaries[arch][0])
|
nuninst[arch] = set(x for x in nuninst_comp[arch] if x in binaries[arch][0])
|
||||||
nuninst[arch + "+all"] = set(x for x in nuninst_comp[arch + "+all"] if x in binaries[arch][0])
|
nuninst[arch + "+all"] = set(x for x in nuninst_comp[arch + "+all"] if x in binaries[arch][0])
|
||||||
|
|
||||||
check_packages(arch, affected, skip_archall, nuninst)
|
check_packages(arch, affected, skip_archall, nuninst)
|
||||||
|
|
||||||
# if we are processing hints, go ahead
|
|
||||||
if hint:
|
|
||||||
nuninst_comp[arch] = nuninst[arch]
|
|
||||||
nuninst_comp[arch + "+all"] = nuninst[arch + "+all"]
|
|
||||||
continue
|
|
||||||
|
|
||||||
# if the uninstallability counter is worse than before, break the loop
|
# if the uninstallability counter is worse than before, break the loop
|
||||||
if ((item.architecture != 'source' and arch not in new_arches) or \
|
if ((item.architecture != 'source' and arch not in new_arches) or \
|
||||||
(arch not in break_arches)) and len(nuninst[arch]) > len(nuninst_comp[arch]):
|
(arch not in break_arches)) and len(nuninst[arch]) > len(nuninst_comp[arch]):
|
||||||
better = False
|
better = False
|
||||||
break
|
break
|
||||||
|
|
||||||
# if we are processing hints or the package is already accepted, go ahead
|
|
||||||
if hint or item in selected: continue
|
|
||||||
|
|
||||||
# check if the action improved the uninstallability counters
|
# check if the action improved the uninstallability counters
|
||||||
if better:
|
if better:
|
||||||
@ -2242,9 +2258,6 @@ class Britney(object):
|
|||||||
# (local-scope) binaries is actually self.binaries["testing"] so we cannot use it here.
|
# (local-scope) binaries is actually self.binaries["testing"] so we cannot use it here.
|
||||||
undo_changes(single_undo, self._inst_tester, sources, self.binaries)
|
undo_changes(single_undo, self._inst_tester, sources, self.binaries)
|
||||||
|
|
||||||
# if we are processing hints, return now
|
|
||||||
if hint:
|
|
||||||
return (nuninst_comp, [])
|
|
||||||
|
|
||||||
self.output_write(" finish: [%s]\n" % ",".join( x.uvname for x in selected ))
|
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("endloop: %s\n" % (self.eval_nuninst(self.nuninst_orig)))
|
||||||
@ -2255,6 +2268,7 @@ class Britney(object):
|
|||||||
|
|
||||||
return (nuninst_comp, extra)
|
return (nuninst_comp, extra)
|
||||||
|
|
||||||
|
|
||||||
def do_all(self, hinttype=None, init=None, actions=None):
|
def do_all(self, hinttype=None, init=None, actions=None):
|
||||||
"""Testing update runner
|
"""Testing update runner
|
||||||
|
|
||||||
@ -2274,6 +2288,7 @@ class Britney(object):
|
|||||||
recurse = True
|
recurse = True
|
||||||
lundo = None
|
lundo = None
|
||||||
nuninst_end = None
|
nuninst_end = None
|
||||||
|
extra = () # empty tuple
|
||||||
|
|
||||||
if hinttype == "easy" or hinttype == "force-hint":
|
if hinttype == "easy" or hinttype == "force-hint":
|
||||||
force = hinttype == "force-hint"
|
force = hinttype == "force-hint"
|
||||||
@ -2298,7 +2313,11 @@ class Britney(object):
|
|||||||
|
|
||||||
if init:
|
if init:
|
||||||
# init => a hint (e.g. "easy") - so do the hint run
|
# init => a hint (e.g. "easy") - so do the hint run
|
||||||
(nuninst_end, extra) = self.iter_packages(init, selected, hint=True, lundo=lundo)
|
nuninst_end = self.iter_packages_hint(selected, lundo=lundo)
|
||||||
|
if recurse:
|
||||||
|
# Ensure upgrade_me and selected do not overlap, if we
|
||||||
|
# follow-up with a recurse ("hint"-hint).
|
||||||
|
upgrade_me = [x for x in upgrade_me if x not in set(selected)]
|
||||||
|
|
||||||
if recurse:
|
if recurse:
|
||||||
# Either the main run or the recursive run of a "hint"-hint.
|
# Either the main run or the recursive run of a "hint"-hint.
|
||||||
@ -2338,7 +2357,7 @@ class Britney(object):
|
|||||||
if recurse:
|
if recurse:
|
||||||
self.upgrade_me = sorted(extra)
|
self.upgrade_me = sorted(extra)
|
||||||
else:
|
else:
|
||||||
self.upgrade_me = [x for x in self.upgrade_me if x not in selected]
|
self.upgrade_me = [x for x in self.upgrade_me if x not in set(selected)]
|
||||||
self.sort_actions()
|
self.sort_actions()
|
||||||
else:
|
else:
|
||||||
self.output_write("FAILED\n")
|
self.output_write("FAILED\n")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user