summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pym/portage_dep.py')
-rw-r--r--pym/portage_dep.py1040
1 files changed, 0 insertions, 1040 deletions
diff --git a/pym/portage_dep.py b/pym/portage_dep.py
deleted file mode 100644
index 66b7bd1..0000000
--- a/pym/portage_dep.py
+++ /dev/null
@@ -1,1040 +0,0 @@
-# deps.py -- Portage dependency resolution functions
-# Copyright 2003-2004 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: /local/data/ulm/cvs/history/var/cvsroot/gentoo-src/portage/pym/portage_dep.py,v 1.35 2005/05/05 06:24:08 jstubbs Exp $
-cvs_id_string="$Id: portage_dep.py,v 1.35 2005/05/05 06:24:08 jstubbs Exp $"[5:-2]
-
-# DEPEND SYNTAX:
-#
-# 'use?' only affects the immediately following word!
-# Nesting is the only legal way to form multiple '[!]use?' requirements.
-#
-# Where: 'a' and 'b' are use flags, and 'z' is a depend atom.
-#
-# "a? z" -- If 'a' in [use], then b is valid.
-# "a? ( z )" -- Syntax with parenthesis.
-# "a? b? z" -- Deprecated.
-# "a? ( b? z )" -- Valid
-# "a? ( b? ( z ) ) -- Valid
-#
-
-import os,string,types,sys,copy
-import portage_exception
-import portage_versions
-import portage_syntax
-
-OPERATORS="*<=>~!"
-ENDVERSION_KEYS = ["pre", "p", "alpha", "beta", "rc"]
-
-def dep_getcpv(s):
- return s.strip(OPERATORS)
-
-def get_operator(mydep):
- """
- returns '~', '=', '>', '<', '=*', '>=', or '<='
- """
-
- if mydep[0] == "~":
- operator = "~"
- elif mydep[0] == "=":
- if mydep[-1] == "*":
- operator = "=*"
- else:
- operator = "="
- elif mydep[0] in "><":
- if len(mydep) > 1 and mydep[1] == "=":
- operator = mydep[0:2]
- else:
- operator = mydep[0]
- else:
- operator = None
- return operator
-
-def isjustname(mypkg):
- myparts=mypkg.split('-')
- for x in myparts:
- if portage_versions.ververify(x):
- return 0
- return 1
-
-
-def isvalidatom(atom):
- mycpv_cps = portage_versions.catpkgsplit(dep_getcpv(atom))
- operator = get_operator(atom)
- if operator:
- if mycpv_cps and mycpv_cps[0] != "null":
- # >=cat/pkg-1.0
- return 1
- else:
- # >=cat/pkg or >=pkg-1.0 (no category)
- return 0
- if mycpv_cps:
- # cat/pkg-1.0
- return 0
- if len(atom.split('/'))==2:
- # cat/pkg
- return 1
- else:
- return 0
-
-
-def strip_empty(myarr):
- for x in range(len(myarr)-1, -1, -1):
- if not myarr[x]:
- del myarr[x]
- return myarr
-
-def paren_reduce(mystr,tokenize=1):
- "Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists"
- mylist = []
- while mystr:
- if ("(" not in mystr) and (")" not in mystr):
- freesec = mystr
- subsec = None
- tail = ""
- elif mystr[0] == ")":
- return [mylist,mystr[1:]]
- elif ("(" in mystr) and (mystr.index("(") < mystr.index(")")):
- freesec,subsec = mystr.split("(",1)
- subsec,tail = paren_reduce(subsec,tokenize)
- else:
- subsec,tail = mystr.split(")",1)
- if tokenize:
- subsec = strip_empty(subsec.split(" "))
- return [mylist+subsec,tail]
- return [mylist+[subsec],tail]
- mystr = tail
- if freesec:
- if tokenize:
- mylist = mylist + strip_empty(freesec.split(" "))
- else:
- mylist = mylist + [freesec]
- if subsec is not None:
- mylist = mylist + [subsec]
- return mylist
-
-def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]):
- """Takes a paren_reduce'd array and reduces the use? conditionals out
- leaving an array with subarrays
- """
- # Quick validity checks
- for x in range(1,len(deparray)):
- if deparray[x] in ["||","&&"]:
- if len(deparray) == x:
- # Operator is the last element
- raise portage_exception.InvalidDependString("INVALID "+deparray[x]+" DEPEND STRING: "+str(deparray))
- if type(deparray[x+1]) != types.ListType:
- # Operator is not followed by a list
- raise portage_exception.InvalidDependString("INVALID "+deparray[x]+" DEPEND STRING: "+str(deparray))
- if deparray and deparray[-1] and deparray[-1][-1] == "?":
- # Conditional with no target
- raise portage_exception.InvalidDependString("INVALID "+deparray[x]+" DEPEND STRING: "+str(deparray))
-
- #XXX: Compatibility -- Still required?
- if ("*" in uselist):
- matchall=1
-
- mydeparray = deparray[:]
- rlist = []
- while mydeparray:
- head = mydeparray.pop(0)
-
- if type(head) == types.ListType:
- rlist = rlist + [use_reduce(head, uselist, masklist, matchall, excludeall)]
-
- else:
- if head[-1] == "?": # Use reduce next group on fail.
- # Pull any other use conditions and the following atom or list into a separate array
- newdeparray = [head]
- while isinstance(newdeparray[-1], str) and newdeparray[-1][-1] == "?":
- if mydeparray:
- newdeparray.append(mydeparray.pop(0))
- else:
- raise ValueError, "Conditional with no target."
-
- # Deprecation checks
- warned = 0
- if len(newdeparray[-1]) == 0:
- sys.stderr.write("Note: Empty target in string. (Deprecated)\n")
- warned = 1
- if len(newdeparray) != 2:
- sys.stderr.write("Note: Nested use flags without parenthesis (Deprecated)\n")
- warned = 1
- if warned:
- sys.stderr.write(" --> "+string.join(map(str,[head]+newdeparray))+"\n")
-
- # Check that each flag matches
- ismatch = True
- for head in newdeparray[:-1]:
- head = head[:-1]
- if head[0] == "!":
- head = head[1:]
- if not matchall and head in uselist or head in excludeall:
- ismatch = False
- break
- elif head not in masklist:
- if not matchall and head not in uselist:
- ismatch = False
- break
- else:
- ismatch = False
-
- # If they all match, process the target
- if ismatch:
- target = newdeparray[-1]
- if isinstance(target, list):
- rlist += [use_reduce(target, uselist, masklist, matchall, excludeall)]
- else:
- rlist += [target]
-
- else:
- rlist += [head]
-
- return rlist
-
-
-def dep_opconvert(deplist):
- """Move || and && to the beginning of the following arrays"""
- # Hack in management of the weird || for dep_wordreduce, etc.
- # dep_opconvert: [stuff, ["||", list, of, things]]
- # At this point: [stuff, "||", [list, of, things]]
- retlist = []
- x = 0
- while x != len(deplist):
- if isinstance(deplist[x], list):
- retlist.append(dep_opconvert(deplist[x]))
- elif deplist[x] == "||" or deplist[x] == "&&":
- retlist.append([deplist[x]] + dep_opconvert(deplist[x+1]))
- x += 1
- else:
- retlist.append(deplist[x])
- x += 1
- return retlist
-
-
-
-
-
-
-class DependencyGraph(object):
- """Self-contained directed graph of abstract nodes.
-
- This is a enhanced version of the digraph class. It supports forward
- and backward dependencies as well as primitive circular dependency
- resolution. It is fully self contained and requires only that nodes
- added to the graph are immutable.
-
- There are no validity checks done on the values passed to any method,
- but is written so that invalid data will either cause an exception to
- be raised. For this reason, this should not be used as part of any
- external API."""
-
-
- def __init__(self):
- """Create an empty graph."""
- # The entire graph is stored inside this one dictionary.
- # The keys represent each node within the graph. Each node
- # is paired with a list of nodes depending on it and a list
- # of nodes it depends on. The complete structure is:
- # { node : ( [node], [node] ) }
- self.graph = {}
-
- # Strictly speaking, the graph shouldn't care about the order
- # that packages are added to the graph, but using it ensures
- # that system packages stay before world packages when pulling
- # nodes one at a time.
- self.order = []
-
- def clone(self):
- """Create an exact duplicate of this graph."""
- clone = DependencyGraph()
- # A manual copy should save a slight amount of time, but
- # is dependent on whether python's deepcopy is implemented
- # in python or not. It is at the moment.
- for node in self.graph:
- clone.graph[node] = (self.graph[node][0][:],
- self.graph[node][1][:])
- clone.order = self.order[:]
- return clone
-
- def has_node(self, node):
- """Indicate the existance of a node in the graph."""
- return self.graph.has_key(node)
-
- def add_node(self, node):
- """Add a node to the graph if it hasn't been already."""
- if self.graph.has_key(node):
- return
- self.graph[node] = ([], [])
- self.order.append(node)
-
- def add_relationship(self, parent, child):
- """Add a relationship between two pre-existing nodes."""
- # This code needs to raise an exception if either the
- # parent or child have not in fact been added prior.
- if parent not in self.graph[child][0]:
- self.graph[child][0].append(parent)
- self.graph[parent][1].append(child)
-
- def remove_relationship(self, parent, child):
- """Remove an existing relationship between two nodes."""
- self.graph[child][0].remove(parent)
- self.graph[parent][1].remove(child)
-
- def get_relationships(self, node):
- """Retrieve parent and children lists of a node.
-
- @rtype: ( [node], [node] )
- """
- # This code also needs to raise an exception if the node
- # has not been added prior.
- relationships = (self.graph[node][0][:],
- self.graph[node][1][:])
- return relationships
-
- def remove_node(self, node):
- """Remove a node from the graph, destroying any relationships.
-
- Any relationships destroyed by removing this node are returned.
-
- @rtype: ( [node], [node] )
- """
- # This code also needs to raise an exception if the node
- # has not been added prior.
-
- relationships = self.get_relationships(node)
-
- # Ensuring that all relationships are destroyed keeps the
- # graph in a sane state. A node must _never_ depend on another
- # node that does not exist in the graph.
- for parent in relationships[0]:
- self.graph[parent][1].remove(node)
- for child in relationships[1]:
- self.graph[child][0].remove(node)
-
- # Kill of the other side of the relationships in one shot.
- del self.graph[node]
-
- # Make sure to remove the node from the ordered list as well.
- self.order.remove(node)
-
- return relationships
-
- def get_all_nodes(self):
- """Return a list of every node in the graph.
-
- @rtype: [node]
- """
- # Assuming our graph is in a sane state, self.order contains
- # the same set of nodes as self.graph.keys().
- return self.order[:]
-
- def get_leaf_nodes(self):
- """Return a list of all nodes that have no child dependencies.
-
- If all nodes have child dependencies and the graph is not
- empty, circular dependency resolution is attempted. In such a
- circumstance, only one node is ever returned and is passed back
- by way of an exception.
-
- @rtype: [node]
- """
- # If the graph is empty, just return an empty list.
- if not self.graph:
- return []
-
- # Iterate through the graph's nodes and add any that have no
- # child dependencies. If we find such nodes, return them.
- nodes = []
- for node in self.order:
- if not self.graph[node][1]:
- nodes.append(node)
- if nodes:
- return nodes
-
- # If we've got this far, then a circular dependency set that
- # contains every node. However, there is usually a subset of
- # nodes that are self-contained. We will find the subset with
- # the most parents so that circular dependencies can be dealt
- # with (and not have to be recalculated) as early as possible.
-
- # Create a list of tuples containing the number of parents
- # paired with the corresponding node.
- counts = []
- # We'll keep a record of the actual parents for later on.
- parents = {}
- for node in self.graph:
- parents[node] = self.get_parent_nodes(node, depth=0)
- if len(parents[node]) == len(self.graph):
- # XXX: Every node in the graph depends on
- # this node. Following the logic through will
- # return this node or another that has equal
- # number of parents, so shortcut it here.
- return [node]
- counts += [(len(parents[node]), node)]
-
- # Reverse sort the generated list.
- counts.sort()
- counts.reverse()
-
- # Find the first node that is in a circular dependency set.
- for count in counts:
- node = count[1]
- children = self.get_child_nodes(node, depth=0)
- if node in children:
- break
-
- # Now we'll order the nodes in the set by parent count.
- counts = []
- for node in children:
- counts += [(len(parents[node]), node)]
-
- # Reverse sort the generated list.
- counts.sort()
- counts.reverse()
-
- # Return the first node in the list.
- # XXX: This needs to be changed into an exception.
- return [counts[0][1]]
-
- def get_root_nodes(self):
- """Return the smallest possible list of starting nodes.
-
- Ordinarily, all nodes with no parent nodes are returned.
- However, if there are any circular dependencies that can
- not be reached through one of these nodes, they will be
- resolved and a suitable starting node chosen.
-
- @rtype: [node]
- """
- # Create a copy of our graph.
- clone = self.clone()
-
- # Keep processing the graph until it is empty.
- roots = []
- while clone.graph:
-
- # Find all nodes that have no parent nodes.
- newroots = []
- for node in clone.order:
- if not clone.graph[node][0]:
- newroots.append(node)
-
- # Remove them and all their descendents from the graph.
- for node in newroots:
- for child in clone.get_child_nodes(node, depth=0):
- clone.remove_node(child)
- clone.remove_node(node)
-
- # And add them to our list of root nodes.
- roots.extend(newroots)
-
- # If the graph is empty, stop processing.
- if not clone.graph:
- break
-
- # If the graph isn't empty, then we have a circular
- # dependency. We'll just remove one leaf node and
- # then look for parentless nodes again.
- clone.remove_node(clone.get_leaf_nodes()[0])
-
- # Sort the list of roots by the node addition order.
- newroots = self.order[:]
- for x in range(len(newroots)-1,-1,-1):
- if newroots[x] not in roots:
- del newroots[x]
-
- # Return the sorted list.
- return newroots
-
- def get_parent_nodes(self, node, depth=1):
- """Return a list of nodes that depend on a node.
-
- The examined node will be included in the returned list
- if the node exists in a circular dependency.
-
- @param depth: Maximum depth to recurse to, or 0 for all.
- @rtype: [node]
- """
- return self.__traverse_nodes(node, depth, 0)
-
- def get_child_nodes(self, node, depth=1):
- """Return a list of nodes depended on by node.
-
- The examined node will be included in the returned list
- if the node exists in a circular dependency.
-
- @param depth: Maximum depth to recurse to, or 0 for all.
- @rtype: [node]
- """
- return self.__traverse_nodes(node, depth, 1)
-
- def __traverse_nodes(self, origin, depth, path):
- # Set depth to the maximum if it is 0.
- if not depth:
- depth = len(self.graph)
-
- traversed = {} # The list of nodes to be returned
-
- # This function _needs_ to be fast, so we use a stack
- # based implementation rather than recursive calls.
- stack = [] # Stack of previous depths
- node = origin # The current node we are checking
- index = 0 # Progress through the node's relations
- length = len(self.graph[node][path])
-
- graph = self.graph # Faster access via local scope
-
- # Repeat while the stack is not empty or there are more
- # relations to be processed for the current node.
- while stack or length != index:
-
- # If we're finished at the current depth, move back up.
- if index == length:
- (depth, node, index, length) = stack.pop()
-
- # Otherwise, process the next relation.
- else:
- relation = graph[node][path][index]
- # Add the relation to our list if necessary...
- if relation not in traversed:
- traversed[relation] = None
- # ...and then check if we can go deeper
- if depth != 1:
- # Add state to the stack.
- stack += [(depth, node, index, length)]
- # Reset state for the new node.
- depth -= 1
- node = relation
- index = 0
- length = len(graph[node][path])
- # Restart the loop.
- continue
-
- # Move onto the next relation.
- index += 1
-
- # Return our list.
- return traversed.keys()
-
-def dep_getkey(mydep):
- if not len(mydep):
- return mydep
- if mydep[0]=="*":
- mydep=mydep[1:]
- if mydep[-1]=="*":
- mydep=mydep[:-1]
- if mydep[0]=="!":
- mydep=mydep[1:]
- if mydep[:2] in [ ">=", "<=" ]:
- mydep=mydep[2:]
- elif mydep[:1] in "=<>~":
- mydep=mydep[1:]
- if isspecific(mydep):
- mysplit=portage_versions.catpkgsplit(mydep)
- if not mysplit:
- return mydep
- return mysplit[0]+"/"+mysplit[1]
- else:
- return mydep
-
-
-iscache={}
-def isspecific(mypkg):
- "now supports packages with no category"
- if mypkg in iscache:
- return iscache[mypkg]
- mysplit=mypkg.split("/")
- if not isjustname(mysplit[-1]):
- iscache[mypkg]=1
- return 1
- iscache[mypkg]=0
- return 0
-
-def match_to_list(mypkg,mylist):
- """(pkgname,list)
- Searches list for entries that matches the package.
- """
- matches=[]
- for x in mylist:
- if match_from_list(x,[mypkg]):
- if x not in matches:
- matches.append(x)
- return matches
-
-def best_match_to_list(mypkg,mylist):
- """(pkgname,list)
- Returns the most specific entry (assumed to be the longest one)
- that matches the package given.
- """
- # XXX Assumption is wrong sometimes.
- maxlen = 0
- bestm = None
- for x in match_to_list(mypkg,mylist):
- if len(x) > maxlen:
- maxlen = len(x)
- bestm = x
- return bestm
-
-
-
-def match_from_list(mydep,candidate_list):
- if mydep[0] == "!":
- mydep = mydep[1:]
-
- mycpv = dep_getcpv(mydep)
- mycpv_cps = portage_versions.catpkgsplit(mycpv) # Can be None if not specific
-
- if not mycpv_cps:
- cat,pkg = portage_versions.catsplit(mycpv)
- ver = None
- rev = None
- else:
- cat,pkg,ver,rev = mycpv_cps
- if mydep == mycpv:
- raise KeyError, "Specific key requires an operator (%s) (try adding an '=')" % (mydep)
-
- if ver and rev:
- operator = get_operator(mydep)
- if not operator:
- writemsg("!!! Invanlid atom: %s\n" % mydep)
- return []
- else:
- operator = None
-
- mylist = []
-
- if operator == None:
- for x in candidate_list:
- xs = portage_versions.pkgsplit(x)
- if xs == None:
- if x != mycpv:
- continue
- elif xs[0] != mycpv:
- continue
- mylist.append(x)
-
- elif operator == "=": # Exact match
- if mycpv in candidate_list:
- mylist = [mycpv]
-
- elif operator == "=*": # glob match
- # The old verion ignored _tag suffixes... This one doesn't.
- for x in candidate_list:
- if x[0:len(mycpv)] == mycpv:
- mylist.append(x)
-
- elif operator == "~": # version, any revision, match
- for x in candidate_list:
- xs = portage_versions.catpkgsplit(x)
- if xs[0:2] != mycpv_cps[0:2]:
- continue
- if xs[2] != ver:
- continue
- mylist.append(x)
-
- elif operator in [">", ">=", "<", "<="]:
- for x in candidate_list:
- try:
- result = portage_versions.pkgcmp(portage_versions.pkgsplit(x), [cat+"/"+pkg,ver,rev])
- except SystemExit, e:
- raise
- except:
- writemsg("\nInvalid package name: %s\n" % x)
- sys.exit(73)
- if result == None:
- continue
- elif operator == ">":
- if result > 0:
- mylist.append(x)
- elif operator == ">=":
- if result >= 0:
- mylist.append(x)
- elif operator == "<":
- if result < 0:
- mylist.append(x)
- elif operator == "<=":
- if result <= 0:
- mylist.append(x)
- else:
- raise KeyError, "Unknown operator: %s" % mydep
- else:
- raise KeyError, "Unknown operator: %s" % mydep
-
- return mylist
-
-
-def prepare_prefdict(preferences):
- myprefdict = {}
- idx = 0
- for atom in preferences:
- if atom.cpv.key not in myprefdict:
- myprefdict[atom.cpv.key] = []
- myprefdict[atom.cpv.key].append((idx, atom))
- idx += 1
- myprefdict["____"] = idx
- return myprefdict
-
-
-def transform_dependspec(dependspec, prefdict):
- def dotransform(dependspec, prefdict):
- dependspec = copy.copy(dependspec)
- elements = dependspec.elements
- dependspec.elements = []
- neworder = []
- prio = prefdict["____"]
- for element in elements[:]:
- if isinstance(element, portage_syntax.DependSpec):
- neworder.append(dotransform(element, prefdict))
- elements.remove(element)
- elif element.cpv.key in prefdict:
- for (idx, pref) in prefdict[element.cpv.key]:
- if pref.intersects(element):
- if idx < prio:
- prio = idx
- if pref.encapsulates(element):
- neworder.append((idx, element))
- elements.remove(element)
- else:
- subdependspec = portage_syntax.DependSpec(element_class=portage_syntax.Atom)
- if element.encapsulates(pref):
- subsubdependspec = portage_syntax.DependSpec(element_class=portage_syntax.Atom)
- subsubdependspec.add_element(pref)
- subsubdependspec.add_element(element)
- subdependspec.add_element(subsubdependspec)
- else:
- subdependspec.add_element(pref)
- subdependspec.add_element(element)
- subdependspec.preferential = True
- neworder.append((idx, subdependspec))
- elements.remove(element)
- neworder.sort()
- for element in neworder:
- dependspec.add_element(element[1])
- for element in elements:
- dependspec.add_element(element)
- return (prio, dependspec)
- return dotransform(dependspec, prefdict)[1]
-
-
-def transform_virtuals(pkg, dependspec, virtuals):
- dependspec = copy.copy(dependspec)
- elements = dependspec.elements
- dependspec.elements = []
- for element in elements:
- if isinstance(element, portage_syntax.DependSpec):
- dependspec.elements.append(transform_virtuals(pkg, element, virtuals))
- elif element.cpv.key not in virtuals:
- dependspec.elements.append(element)
- else:
- subdepspec = portage_syntax.DependSpec(element_class=portage_syntax.Atom)
- subdepspec.preferential = True
- for virtual in virtuals[element.cpv.key]:
- atom = element.with_key(virtual)
- if not atom.match(pkg):
- subdepspec.add_element(element.with_key(virtual))
- dependspec.elements.append(subdepspec)
- return dependspec
-
-
-class StateGraph(object):
-
- def __init__(self):
- # key : (bool, [GluePkg], [GluePkg], [Atom], [Atom])
- self.pkgrec = {}
- # key : [Atom]
- self.unmatched_atoms = {}
- # [Atom]
- self.unmatched_preferentials = []
- # key : [pkg, [[Atom]]]
- self.preferential_atoms = {}
- # key : [key]
- self.reverse_preferentials = {}
-
- def get_unmatched_atoms(self):
- unmatched = []
- for key in self.unmatched_atoms:
- unmatched.append(self.unmatched_atoms[key][0])
- return unmatched
-
- def get_unmatched_preferentials(self):
- return self.unmatched_preferentials[:]
-
- def get_unneeded_packages(self):
- unneeded = []
- for key in self.pkgrec:
- unneeded.extend(self.pkgrec[key][1])
- return unneeded
-
- def get_needed_packages(self):
- needed = []
- for key in self.pkgrec:
- needed.extend(self.pkgrec[key][0])
- return needed
-
- def get_conflicts(self):
- conflicts = []
- for key in self.pkgrec:
- slots = {}
- in_conflict = False
- for pkg in self.pkgrec[key][0]:
- if pkg.slot in slots:
- slots[pkg.slot].append(pkg)
- in_conflict = True
- else:
- slots[pkg.slot] = [pkg]
- if in_conflict:
- for slot in slots:
- if len(slots[slot]) > 1:
- conflicts.append(slots[slot])
- return conflicts
-
- def add_package(self, pkg, keep=False):
- key = pkg.key
- if key not in self.pkgrec:
- self.pkgrec[key] = ([], [pkg], [], [], [keep])
- else:
- if not self.pkgrec[key][4][0]:
- self.pkgrec[key][4][0] = keep
- self.pkgrec[key][1].append(pkg)
- self._recheck(key)
-
- def remove_package(self, pkg):
- key = pkg.key
- if pkg not in self.pkgrec[key][1]:
- self._demote_pkg(pkg)
- self.pkgrec[key][1].remove(pkg)
- self._recheck(key)
-
- def _recheck(self, key):
- (used, unused, unmatched) = self._select_pkgs(key)
- for pkg in used:
- if pkg not in self.pkgrec[key][0]:
- self._promote_pkg(pkg)
- for pkg in unused:
- if pkg not in self.pkgrec[key][1]:
- self._demote_pkg(pkg)
- if key in self.unmatched_atoms:
- del self.unmatched_atoms[key]
- for idx in range(len(self.unmatched_preferentials)-1, -1, -1):
- if self.unmatched_preferentials[idx].cpv.key == key:
- del self.unmatched_preferentials[idx]
- if unmatched:
- for atom in unmatched:
- if atom in self.pkgrec[key][2]:
- if key in self.unmatched_atoms:
- self.unmatched_atoms[key].append(atom)
- else:
- self.unmatched_atoms[key] = [atom]
- else:
- self.unmatched_preferentials.append(atom)
- if not self.pkgrec[key][0] and not self.pkgrec[key][1] and not self.pkgrec[key][2] and not self.pkgrec[key][3] and not self.pkgrec[key][4][0]:
- del self.pkgrec[key]
-
- def _select_pkgs(self, key):
- allpkgs = self.pkgrec[key][0] + self.pkgrec[key][1]
- used = []
- unused = []
- regular_atoms = []
- unmatched = []
- for atom in self.pkgrec[key][2] + self.pkgrec[key][3]:
- if atom.blocks:
- for pkg in allpkgs[:]:
- if atom.match(pkg):
- allpkgs.remove(pkg)
- unused.append(pkg)
- elif atom not in regular_atoms:
- regular_atoms.append(atom)
-
- if regular_atoms:
- slots = {}
- for pkg in allpkgs:
- if pkg.slot not in slots:
- slots[pkg.slot] = []
- slots[pkg.slot].append(pkg)
-
- used_slots = []
- multislot_atoms = []
- for atom in regular_atoms:
- matched_slots = []
- for slot in slots:
- for pkg in slots[slot]:
- if atom.match(pkg):
- matched_slots.append(slot)
- break
- if len(matched_slots) > 1:
- multislot_atoms.append(atom)
- break
- if atom in multislot_atoms:
- continue
- if not matched_slots:
- unmatched.append(atom)
- continue
- slot = matched_slots[0]
- if slot not in used_slots:
- used_slots.append(slot)
- for idx in range(len(slots[slot])-1, -1, -1):
- if not atom.match(slots[slot][idx]):
- unused.append(slots[slot][idx])
- del slots[slot][idx]
- used = []
- uncertain = []
- for slot in slots:
- if slot in used_slots:
- used.extend(slots[slot])
- else:
- uncertain.extend(slots[slot])
- for atom in multislot_atoms:
- matched = False
- for pkg in used[:]:
- if atom.match(pkg):
- matched = True
- break
- if matched:
- continue
- for pkg in uncertain:
- if atom.match(pkg):
- uncertain.remove(pkg)
- used.append(pkg)
- matched = True
- break
- if not matched:
- unmatched.append(atom)
- unused.extend(uncertain)
- elif self.pkgrec[key][4][0]:
- used = allpkgs
- else:
- unused = allpkgs
- return (used, unused, unmatched)
-
- def _promote_pkg(self, pkg):
- key = pkg.key
- checks = {}
- self.pkgrec[key][1].remove(pkg)
- self.pkgrec[key][0].append(pkg)
- if not pkg.rdeps.preferential:
- for atom in pkg.rdeps.elements:
- if atom.cpv.key not in self.pkgrec:
- self.pkgrec[atom.cpv.key] = ([], [], [atom], [], [False])
- else:
- self.pkgrec[atom.cpv.key][2].append(atom)
- if atom.cpv.key not in checks:
- checks[atom.cpv.key] = True
- else:
- preflist = [pkg, []]
- if isinstance(pkg.rdeps.elements[0], portage_syntax.Atom):
- for atom in pkg.rdeps.elements:
- preflist[1].append([atom])
- else:
- for option in pkg.rdeps.elements:
- preflist[1].append([])
- for atom in option.elements:
- preflist[1][-1].append(atom)
- for option in preflist[1]:
- for atom in option:
- if atom.cpv.key not in self.pkgrec:
- self.pkgrec[atom.cpv.key] = ([], [], [], [atom], [False])
- else:
- self.pkgrec[atom.cpv.key][3].append(atom)
- if atom.cpv.key not in self.reverse_preferentials:
- self.reverse_preferentials[atom.cpv.key] = {}
- if key not in self.reverse_preferentials[atom.cpv.key]:
- self.reverse_preferentials[atom.cpv.key][key] = 1
- else:
- self.reverse_preferentials[atom.cpv.key][key] += 1
- checks[atom.cpv.key] = True
- if key not in self.preferential_atoms:
- self.preferential_atoms[key] = [preflist]
- else:
- self.preferential_atoms[key].append(preflist)
- self._check_preferentials(key)
- if key in self.reverse_preferentials:
- for parent in self.reverse_preferentials[key].keys():
- self._check_preferentials(parent)
- for key in checks:
- if key in self.pkgrec:
- self._recheck(key)
-
- def _demote_pkg(self, pkg):
- key = pkg.key
- checks = {}
- self.pkgrec[key][0].remove(pkg)
- self.pkgrec[key][1].append(pkg)
- if not pkg.rdeps.preferential:
- for atom in pkg.rdeps.elements:
- self.pkgrec[atom.cpv.key][2].remove(atom)
- if not self.pkgrec[atom.cpv.key][0] and not self.pkgrec[atom.cpv.key][1] and not self.pkgrec[atom.cpv.key][2] and not self.pkgrec[atom.cpv.key][3]:
- del self.pkgrec[atom.cpv.key]
- if atom.cpv.key in self.unmatched_atoms:
- del self.unmatched_atoms[atom.cpv.key]
- else:
- checks[atom.cpv.key] = True
- else:
- for idx in range(len(self.preferential_atoms[key])):
- if self.preferential_atoms[key][idx][0] == pkg:
- for atomlist in self.preferential_atoms[key][idx][1]:
- for atom in atomlist:
- self.pkgrec[atom.cpv.key][3].remove(atom)
- self.reverse_preferentials[atom.cpv.key][key] -= 1
- if not self.reverse_preferentials[atom.cpv.key][key]:
- del self.reverse_preferentials[atom.cpv.key][key]
- if not self.reverse_preferentials[atom.cpv.key]:
- del self.reverse_preferentials[atom.cpv.key]
- checks[atom.cpv.key] = True
- del self.preferential_atoms[key][idx]
- if not self.preferential_atoms[key]:
- del self.preferential_atoms[key]
- if key in self.reverse_preferentials:
- for parent in self.reverse_preferentials[key].keys():
- self._check_preferentials(parent)
- for key in checks:
- if key in self.pkgrec:
- self._recheck(key)
-
- def _check_preferentials(self, key):
- checks = {}
- for preflist in self.preferential_atoms[key]:
- if len(preflist[1]) == 1:
- all_matched = True
- for atom in preflist[1][0]:
- matched = False
- for pkg in self.pkgrec[atom.cpv.key][0]:
- if atom.match(pkg):
- matched = True
- break
- if not matched:
- all_matched = False
- break
- if not all_matched:
- pkg = preflist[0]
- self._demote_pkg(pkg)
- self._promote_pkg(pkg)
- self._check_preferentials(key)
- return
- else:
- for idx in range(len(preflist[1])):
- all_matched = True
- for atom in preflist[1][idx]:
- matched = False
- for pkg in self.pkgrec[atom.cpv.key][0]:
- if atom.match(pkg):
- matched = True
- break
- if not matched:
- all_matched = False
- break
- if all_matched:
- removable = preflist[1][:idx] + preflist[1][idx+1:]
- preflist[1] = [preflist[1][idx]]
- for option in removable:
- for atom in option:
- self.pkgrec[atom.cpv.key][3].remove(atom)
- self.reverse_preferentials[atom.cpv.key][key] -= 1
- if not self.reverse_preferentials[atom.cpv.key][key]:
- del self.reverse_preferentials[atom.cpv.key][key]
- if not self.reverse_preferentials[atom.cpv.key]:
- del self.reverse_preferentials[atom.cpv.key]
- checks[atom.cpv.key] = True
- break
- for key in checks:
- self._recheck(key)