mirror of
https://github.com/flatcar/scripts.git
synced 2025-09-24 15:11:19 +02:00
Cleanup cycle cracking in parallel_emerge.
I've cleaned up the cycle cracking in parallel_emerge to hopefully be significantly easier to understand. This also fixes some bugs. Most significantly, this patch restores the dependency cracking so that it actually cracks cycles that are against the emerge ordering, instead of cracking everything but those dependencies. This was only broken temporarily due to my fix for Bug 5795. Oops. Fortunately, this bug doesn't affect many people, because make_chroot --fast is deprecated anyway. TEST=make_chroot --fast, parallel_emerge -pe hard-host-depends BUG=chromium-os:5795 Review URL: http://codereview.chromium.org/3184011
This commit is contained in:
parent
64541ede55
commit
ddc372597f
@ -642,39 +642,44 @@ class DepGraphGenerator(object):
|
||||
"""Find cycles in the dependency tree.
|
||||
|
||||
Returns:
|
||||
Dict of packages involved in cyclic dependencies, mapping each package
|
||||
to a list of the cycles the package is involved in.
|
||||
A dict mapping cyclic packages to a dict of the deps that cause
|
||||
cycles. For each dep that causes cycles, it returns an example
|
||||
traversal of the graph that shows the cycle.
|
||||
"""
|
||||
|
||||
def FindCyclesAtNode(pkg, cycles, unresolved):
|
||||
def FindCyclesAtNode(pkg, cycles, unresolved, resolved):
|
||||
"""Find cycles in cyclic dependencies starting at specified package.
|
||||
|
||||
Args:
|
||||
pkg: Package identifier.
|
||||
cycles: Set of cycles so far.
|
||||
cycles: A dict mapping cyclic packages to a dict of the deps that
|
||||
cause cycles. For each dep that causes cycles, it returns an
|
||||
example traversal of the graph that shows the cycle.
|
||||
unresolved: Nodes that have been visited but are not fully processed.
|
||||
resolved: Nodes that have been visited and are fully processed.
|
||||
"""
|
||||
pkg_cycles = cycles.get(pkg)
|
||||
if pkg in resolved and not pkg_cycles:
|
||||
# If we already looked at this package, and found no cyclic
|
||||
# dependencies, we can stop now.
|
||||
return
|
||||
unresolved.append(pkg)
|
||||
mycycles = cycles.get(pkg)
|
||||
if mycycles:
|
||||
mycycles = mycycles.get("pkgs")
|
||||
for dep in deps_map[pkg]["needs"]:
|
||||
if mycycles and dep in mycycles:
|
||||
continue
|
||||
elif dep in unresolved:
|
||||
if dep in unresolved:
|
||||
idx = unresolved.index(dep)
|
||||
mycycle = unresolved[idx:] + [dep]
|
||||
for cycle_pkg in mycycle:
|
||||
info = cycles.setdefault(cycle_pkg, {})
|
||||
info.setdefault("pkgs", set()).update(mycycle)
|
||||
info.setdefault("cycles", []).append(mycycle)
|
||||
else:
|
||||
FindCyclesAtNode(dep, cycles, unresolved)
|
||||
for i in range(len(mycycle) - 1):
|
||||
pkg1, pkg2 = mycycle[i], mycycle[i+1]
|
||||
cycles.setdefault(pkg1, {}).setdefault(pkg2, mycycle)
|
||||
elif not pkg_cycles or dep not in pkg_cycles:
|
||||
# Looks like we haven't seen this edge before.
|
||||
FindCyclesAtNode(dep, cycles, unresolved, resolved)
|
||||
unresolved.pop()
|
||||
resolved.add(pkg)
|
||||
|
||||
cycles, unresolved = {}, []
|
||||
cycles, unresolved, resolved = {}, [], set()
|
||||
for pkg in deps_map:
|
||||
FindCyclesAtNode(pkg, cycles, unresolved)
|
||||
FindCyclesAtNode(pkg, cycles, unresolved, resolved)
|
||||
return cycles
|
||||
|
||||
def RemoveInstalledPackages():
|
||||
@ -736,6 +741,31 @@ class DepGraphGenerator(object):
|
||||
target_needs.pop(target, None)
|
||||
del deps_map[pkg]
|
||||
|
||||
def PrintCycleBreak(basedep, dep, mycycle):
|
||||
"""Print details about a cycle that we are planning on breaking.
|
||||
|
||||
We are breaking a cycle where dep needs basedep. mycycle is an
|
||||
example cycle which contains dep -> basedep."""
|
||||
|
||||
# If it's an optional dependency, there's no need to spam the user with
|
||||
# warning messages.
|
||||
needs = deps_map[dep]["needs"]
|
||||
depinfo = needs.get(basedep, "deleted")
|
||||
if depinfo == "optional":
|
||||
return
|
||||
|
||||
# Notify the user that we're breaking a cycle.
|
||||
print "Breaking %s -> %s (%s)" % (dep, basedep, depinfo)
|
||||
|
||||
# Show cycle.
|
||||
for i in range(len(mycycle) - 1):
|
||||
pkg1, pkg2 = mycycle[i], mycycle[i+1]
|
||||
needs = deps_map[pkg1]["needs"]
|
||||
depinfo = needs.get(pkg2, "deleted")
|
||||
if pkg1 == dep and pkg2 == basedep:
|
||||
depinfo = depinfo + ", deleting"
|
||||
print " %s -> %s (%s)" % (pkg1, pkg2, depinfo)
|
||||
|
||||
def SanitizeTree(cycles):
|
||||
"""Remove circular dependencies.
|
||||
|
||||
@ -752,25 +782,12 @@ class DepGraphGenerator(object):
|
||||
package to a list of the cycles the package is involved in. Produced
|
||||
by FindCycles().
|
||||
"""
|
||||
for basedep, cycle_info in cycles.iteritems():
|
||||
for mycycle in cycle_info["cycles"]:
|
||||
info = []
|
||||
broken = False
|
||||
for i in range(len(mycycle) - 1):
|
||||
pkg1, pkg2 = mycycle[i], mycycle[i+1]
|
||||
needs = deps_map[pkg1]["needs"]
|
||||
depinfo = needs.get(pkg2, "deleted")
|
||||
bad = False
|
||||
if (deps_info[pkg1]["idx"] >= deps_info[pkg2]["idx"] and
|
||||
depinfo != "deleted"):
|
||||
depinfo = depinfo + ", deleting"
|
||||
broken = True
|
||||
del deps_map[pkg1]["needs"][pkg2]
|
||||
deps_map[pkg2]["provides"].remove(pkg1)
|
||||
info.append(" %s -> %s (%s)" % (pkg1, pkg2, depinfo))
|
||||
if broken:
|
||||
print "Breaking cycle:"
|
||||
print "\n".join(info)
|
||||
for dep, mycycles in cycles.iteritems():
|
||||
for basedep, mycycle in mycycles.iteritems():
|
||||
if deps_info[basedep]["idx"] >= deps_info[dep]["idx"]:
|
||||
PrintCycleBreak(basedep, dep, mycycle)
|
||||
del deps_map[dep]["needs"][basedep]
|
||||
deps_map[basedep]["provides"].remove(dep)
|
||||
|
||||
def AddSecretDeps():
|
||||
"""Find these tagged packages and add extra dependencies.
|
||||
|
Loading…
x
Reference in New Issue
Block a user