Improved performances sorting in a smart way the list of actions (only enabled if --compatible is not used).

bzr-import-20160707
Fabio Tranchitella 19 years ago
parent dc1a84151d
commit 90768aa4e3

@ -1,7 +1,3 @@
# TODO: # Unsatisfable dependencies are not valid candidates, please drop them from upgrade_me (waiting reply from aba)
# Add support for old libraries (introducing a new operation: remove single binary) # Add support for old libraries (introducing a new operation: remove single binary)
# Add support for udeb # Add support for udeb
# DONE:
# Conflicts: work, we should try to solve the problem in a smarter way (without computing the full closed graph)
# Add support for calling britney from command line

@ -243,6 +243,7 @@ class Britney:
self.approvals = self.read_approvals(self.options.tpu) self.approvals = self.read_approvals(self.options.tpu)
self.hints = self.read_hints(self.options.unstable) self.hints = self.read_hints(self.options.unstable)
self.excuses = [] self.excuses = []
self.dependencies = {}
def __parse_arguments(self): def __parse_arguments(self):
"""Parse the command line arguments """Parse the command line arguments
@ -762,7 +763,7 @@ class Britney:
return (len(packages) > 0, packages) return (len(packages) > 0, packages)
def excuse_unsat_deps(self, pkg, src, arch, suite, excuse=None, excluded=[], conflicts=False): def excuse_unsat_deps(self, pkg, src, arch, suite, excuse, excluded=[], conflicts=False):
"""Find unsatisfied dependencies for a binary package """Find unsatisfied dependencies for a binary package
This method analyzes the dependencies of the binary package specified This method analyzes the dependencies of the binary package specified
@ -779,6 +780,7 @@ class Britney:
# local copies for better performances # local copies for better performances
parse_depends = apt_pkg.ParseDepends parse_depends = apt_pkg.ParseDepends
get_dependency_solvers = self.get_dependency_solvers get_dependency_solvers = self.get_dependency_solvers
strict = not self.options.compatible
# analyze the dependency fields (if present) # analyze the dependency fields (if present)
for type in ('Pre-Depends', 'Depends'): for type in ('Pre-Depends', 'Depends'):
@ -789,11 +791,15 @@ class Britney:
# for every block of dependency (which is formed as conjunction of disconjunction) # for every block of dependency (which is formed as conjunction of disconjunction)
for block, block_txt in zip(parse_depends(binary_u[type_key]), binary_u[type_key].split(',')): for block, block_txt in zip(parse_depends(binary_u[type_key]), binary_u[type_key].split(',')):
# if the block is satisfied in testing, then skip the block # if the block is satisfied in testing, then skip the block
solved, packages = get_dependency_solvers(block, arch, 'testing', excluded, strict=(excuse == None)) solved, packages = get_dependency_solvers(block, arch, 'testing', excluded, strict=strict)
if solved: continue if solved:
for p in packages:
if p not in self.binaries[suite][arch][0]: continue
excuse.add_sane_dep(self.binaries[suite][arch][0][p]['source'])
continue
# check if the block can be satisfied in unstable, and list the solving packages # check if the block can be satisfied in unstable, and list the solving packages
solved, packages = get_dependency_solvers(block, arch, suite) solved, packages = get_dependency_solvers(block, arch, suite, [], strict=strict)
packages = [self.binaries[suite][arch][0][p]['source'] for p in packages] packages = [self.binaries[suite][arch][0][p]['source'] for p in packages]
# if the dependency can be satisfied by the same source package, skip the block: # if the dependency can be satisfied by the same source package, skip the block:
@ -803,6 +809,8 @@ class Britney:
# if no package can satisfy the dependency, add this information to the excuse # if no package can satisfy the dependency, add this information to the excuse
if len(packages) == 0: if len(packages) == 0:
excuse.addhtml("%s/%s unsatisfiable %s: %s" % (pkg, arch, type, block_txt.strip())) excuse.addhtml("%s/%s unsatisfiable %s: %s" % (pkg, arch, type, block_txt.strip()))
if arch not in self.options.break_arches: excuse.add_unsat_dep(arch)
continue
# for the solving packages, update the excuse to add the dependencies # for the solving packages, update the excuse to add the dependencies
for p in packages: for p in packages:
@ -1791,6 +1799,11 @@ class Britney:
final result is successful, otherwise (None, None). final result is successful, otherwise (None, None).
""" """
extra = [] extra = []
deferred = []
skipped = []
mark_passed = False
position = len(packages)
nuninst_comp = self.get_nuninst() nuninst_comp = self.get_nuninst()
# local copies for better performances # local copies for better performances
@ -1801,12 +1814,34 @@ class Britney:
nobreakall_arches = self.options.nobreakall_arches nobreakall_arches = self.options.nobreakall_arches
new_arches = self.options.new_arches new_arches = self.options.new_arches
break_arches = self.options.break_arches break_arches = self.options.break_arches
dependencies = self.dependencies
compatible = self.options.compatible
output.write("recur: [%s] %s %d/%d\n" % (",".join(self.selected), "", len(packages), len(extra))) output.write("recur: [%s] %s %d/%d\n" % (",".join(self.selected), "", len(packages), len(extra)))
# loop on the packages (or better, actions) # loop on the packages (or better, actions)
while packages: while packages:
pkg = packages.pop(0) pkg = 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
continue
else: position -= 1
# defer packages if their dependency has been already skipped
if not compatible and not mark_passed:
defer = False
for p in dependencies.get(pkg, []):
if p in skipped:
deferred.append(pkg)
skipped.append(pkg)
defer = True
break
if defer: continue
output.write("trying: %s\n" % (pkg)) output.write("trying: %s\n" % (pkg))
better = True better = True
@ -1890,7 +1925,10 @@ class Britney:
output.write("skipped: %s (%d <- %d)\n" % (pkg, len(extra), len(packages))) output.write("skipped: %s (%d <- %d)\n" % (pkg, len(extra), len(packages)))
output.write(" got: %s\n" % (self.eval_nuninst(nuninst, "/" in pkg and nuninst_comp or None))) output.write(" got: %s\n" % (self.eval_nuninst(nuninst, "/" in pkg and nuninst_comp or None)))
output.write(" * %s: %s\n" % (arch, ", ".join(sorted([b for b in broken if b not in nuninst_comp[arch]])))) output.write(" * %s: %s\n" % (arch, ", ".join(sorted([b for b in broken if b not in nuninst_comp[arch]]))))
extra.append(pkg) extra.append(pkg)
if not mark_passed:
skipped.append(pkg)
# undo the changes (source) # undo the changes (source)
for k in undo['sources'].keys(): for k in undo['sources'].keys():
@ -1971,26 +2009,47 @@ class Britney:
output.close() output.close()
self.__log("Test completed!", type="I") self.__log("Test completed!", type="I")
def main(self): def sort_actions(self):
"""Main method """Sort actions in a smart way
This is the entry point for the class: it includes the list of calls This method sorts the list of actions in a smart way. In details, it uses
for the member methods which will produce the output files. as base sort the number of days the excuse is old, then reordering packages
so the ones with most reverse dependencies are at the end of the loop.
If an action depends on another one, it is put after it.
""" """
if not self.options.actions:
self.write_excuses()
if not self.options.compatible:
upgrade_me = [x.name for x in self.excuses if x.name in self.upgrade_me] upgrade_me = [x.name for x in self.excuses if x.name in self.upgrade_me]
for e in self.excuses: for e in self.excuses:
if e.name not in upgrade_me: continue if e.name not in upgrade_me: continue
if e.name.startswith("-"): # try removes at the end of the loop
elif e.name[0] == '-':
upgrade_me.remove(e.name) upgrade_me.remove(e.name)
upgrade_me.append(e.name) upgrade_me.append(e.name)
if len(e.deps) > 0: # otherwise, put it in a good position checking its dependencies
else:
pos = []
udeps = [upgrade_me.index(x) for x in e.deps if x in upgrade_me and x != e.name]
if len(udeps) > 0:
pos.append(max(udeps))
sdeps = [upgrade_me.index(x) for x in e.sane_deps if x in upgrade_me and x != e.name]
if len(sdeps) > 0:
pos.append(min(sdeps))
if len(pos) == 0: continue
upgrade_me.remove(e.name) upgrade_me.remove(e.name)
pos = max([upgrade_me.index(x) for x in e.deps if x in upgrade_me]) upgrade_me.insert(max(pos)+1, e.name)
upgrade_me.insert(pos+1, e.name) self.dependencies[e.name] = e.deps
# replace the list of actions with the new one
self.upgrade_me = upgrade_me self.upgrade_me = upgrade_me
def main(self):
"""Main method
This is the entry point for the class: it includes the list of calls
for the member methods which will produce the output files.
"""
if not self.options.actions:
self.write_excuses()
if not self.options.compatible:
self.sort_actions()
else: self.upgrade_me = self.options.actions.split() else: self.upgrade_me = self.options.actions.split()
self.upgrade_testing() self.upgrade_testing()

@ -54,7 +54,9 @@ class Excuse:
self.invalid_deps = [] self.invalid_deps = []
self.deps = [] self.deps = []
self.sane_deps = []
self.break_deps = [] self.break_deps = []
self.unsat_deps = {}
self.bugs = [] self.bugs = []
self.htmlline = [] self.htmlline = []
@ -87,11 +89,19 @@ class Excuse:
"""Add a dependency""" """Add a dependency"""
if name not in self.deps: self.deps.append(name) if name not in self.deps: self.deps.append(name)
def add_sane_dep(self, name):
"""Add a sane dependency"""
if name not in self.sane_deps: self.sane_deps.append(name)
def add_break_dep(self, name, arch): def add_break_dep(self, name, arch):
"""Add a break dependency""" """Add a break dependency"""
if (name, arch) not in self.break_deps: if (name, arch) not in self.break_deps:
self.break_deps.append( (name, arch) ) self.break_deps.append( (name, arch) )
def add_unsat_dep(self, arch):
"""Add a flag for unsatisfied dependencies"""
self.unsat_deps[arch] = True
def invalidate_dep(self, name): def invalidate_dep(self, name):
"""Invalidate dependency""" """Invalidate dependency"""
if name not in self.invalid_deps: self.invalid_deps.append(name) if name not in self.invalid_deps: self.invalid_deps.append(name)

Loading…
Cancel
Save