levels:
MEDIUM The upper boundary for medium dependencies.
+ MEDIUM_SOFT The upper boundary for medium-soft dependencies.
SOFT The upper boundary for soft dependencies.
MIN The lower boundary for soft dependencies.
"""
- __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime")
+ __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime", "runtime_post")
MEDIUM = -1
- SOFT = -2
- MIN = -4
+ MEDIUM_SOFT = -2
+ SOFT = -3
+ MIN = -6
def __init__(self, **kwargs):
for myattr in self.__slots__:
if myattr == "__weakref__":
return 0
if self.runtime:
return -1
+ if self.runtime_post:
+ return -2
if self.buildtime:
- return -2
- if self.runtime:
return -3
- return -4
+ if self.runtime:
+ return -4
+ if self.runtime_post:
+ return -5
+ return -6
def __lt__(self, other):
return self.__int__() < other
def __le__(self, other):
myvalue = self.__int__()
if myvalue > self.MEDIUM:
return "hard"
- if myvalue > self.SOFT:
+ if myvalue > self.MEDIUM_SOFT:
return "medium"
+ if myvalue > self.SOFT:
+ return "medium-soft"
return "soft"
class FakeVartree(portage.vartree):
# Post Depend -- Add to the list without a parent, as it depends
# on a package being present AND must be built after that package.
if not self.select_dep(myroot, edepend["PDEPEND"], myparent=mp,
- myuse=myuse, priority=DepPriority(), rev_deps=True,
+ myuse=myuse, priority=DepPriority(runtime_post=True),
parent_arg=arg):
return 0
except ValueError, e:
if "portage" == portage.catsplit(portage.dep_getkey(cpv))[-1]:
asap_nodes.append(node)
break
- ignore_priority_range = [None]
- ignore_priority_range.extend(
- xrange(DepPriority.MIN, DepPriority.MEDIUM + 1))
+ ignore_priority_soft_range = [None]
+ ignore_priority_soft_range.extend(
+ xrange(DepPriority.MIN, DepPriority.SOFT + 1))
tree_mode = "--tree" in self.myopts
+ # Tracks whether or not the current iteration should prefer asap_nodes
+ # if available. This is set to False when the previous iteration
+ # failed to select any nodes. It is reset whenever nodes are
+ # successfully selected.
+ prefer_asap = True
while not mygraph.empty():
- ignore_priority = None
- nodes = None
- if asap_nodes:
+ selected_nodes = None
+ if prefer_asap and asap_nodes:
"""ASAP nodes are merged before their soft deps."""
+ asap_nodes = [node for node in asap_nodes \
+ if mygraph.contains(node)]
for node in asap_nodes:
- if not mygraph.contains(node):
- asap_nodes.remove(node)
- continue
if not mygraph.child_nodes(node,
ignore_priority=DepPriority.SOFT):
- nodes = [node]
+ selected_nodes = [node]
asap_nodes.remove(node)
break
- if not nodes:
- for ignore_priority in ignore_priority_range:
+ if not selected_nodes and \
+ not (prefer_asap and asap_nodes):
+ for ignore_priority in ignore_priority_soft_range:
nodes = get_nodes(ignore_priority=ignore_priority)
if nodes:
break
- selected_nodes = None
- if nodes:
- if ignore_priority <= DepPriority.SOFT:
+ if nodes:
if ignore_priority is None and not tree_mode:
# Greedily pop all of these nodes since no relationship
# has been ignored. This optimization destroys --tree
if not selected_nodes:
# settle for a root node
selected_nodes = [nodes[0]]
- else:
+ if not selected_nodes:
+ nodes = get_nodes(ignore_priority=DepPriority.MEDIUM)
+ if nodes:
"""Recursively gather a group of nodes that RDEPEND on
eachother. This ensures that they are merged as a group
and get their RDEPENDs satisfied as soon as possible."""
- def gather_deps(mergeable_nodes, selected_nodes, node):
+ def gather_deps(ignore_priority,
+ mergeable_nodes, selected_nodes, node):
if node in selected_nodes:
return True
if node not in mergeable_nodes:
return False
selected_nodes.add(node)
for child in mygraph.child_nodes(node,
- ignore_priority=DepPriority.SOFT):
- if not gather_deps(
+ ignore_priority=ignore_priority):
+ if not gather_deps(ignore_priority,
mergeable_nodes, selected_nodes, child):
return False
return True
mergeable_nodes = set(nodes)
- for node in nodes:
- selected_nodes = set()
- if gather_deps(
- mergeable_nodes, selected_nodes, node):
+ if prefer_asap and asap_nodes:
+ nodes = asap_nodes
+ for ignore_priority in xrange(DepPriority.SOFT,
+ DepPriority.MEDIUM_SOFT + 1):
+ for node in nodes:
+ selected_nodes = set()
+ if gather_deps(ignore_priority,
+ mergeable_nodes, selected_nodes, node):
+ break
+ else:
+ selected_nodes = None
+ if selected_nodes:
break
- else:
- selected_nodes = None
+
+ if prefer_asap and asap_nodes and not selected_nodes:
+ # We failed to find any asap nodes to merge, so ignore
+ # them for the next iteration.
+ prefer_asap = False
+ continue
+
+ if selected_nodes and ignore_priority > DepPriority.SOFT:
+ # Try to merge ignored medium deps as soon as possible.
+ for node in selected_nodes:
+ children = set(mygraph.child_nodes(node))
+ soft = children.difference(
+ mygraph.child_nodes(node,
+ ignore_priority=DepPriority.SOFT))
+ medium_soft = children.difference(
+ mygraph.child_nodes(node,
+ ignore_priority=DepPriority.MEDIUM_SOFT))
+ medium_soft.difference_update(soft)
+ for child in medium_soft:
+ if child in selected_nodes:
+ continue
+ if child in asap_nodes:
+ continue
+ # TODO: Try harder to make these nodes get
+ # merged absolutely as soon as possible.
+ asap_nodes.append(child)
if not selected_nodes:
if not myblockers.is_empty():
print "!!! disabling USE flags that trigger optional dependencies."
sys.exit(1)
+ # At this point, we've succeeded in selecting one or more nodes, so
+ # it's now safe to reset the prefer_asap to it's default state.
+ prefer_asap = True
+
for node in selected_nodes:
retlist.append(list(node))
mygraph.remove(node)