Chase Zach, merged from trunk 4696:4701
authorFabian Groffen <grobian@gentoo.org>
Sun, 15 Oct 2006 07:09:35 +0000 (07:09 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sun, 15 Oct 2006 07:09:35 +0000 (07:09 -0000)
svn path=/main/branches/prefix/; revision=4703

bin/ebuild.sh
bin/emerge

index 5a6ae5030172503ad3cad15617d2d816a75293a0..1eab788a705cf23ba5e1425aaf0304635d073490 100755 (executable)
@@ -1320,7 +1320,11 @@ inherit() {
                PECLASS="$ECLASS"
                export ECLASS="$1"
 
-               if [ "$EBUILD_PHASE" != "depend" ]; then
+               if [ "${EBUILD_PHASE}" != "depend" ] && \
+                       [[ ${EBUILD_PHASE} != *rm ]]; then
+                       # This is disabled in the *rm phases because they frequently give
+                       # false alarms due to INHERITED in /var/db/pkg being outdated
+                       # in comparison the the eclasses from the portage tree.
                        if ! hasq $ECLASS $INHERITED; then
                                vecho
                                vecho "QA Notice: ECLASS '$ECLASS' inherited illegally in $CATEGORY/$PF" >&2
index 1effb0e13a1ba3487b39f813a1920f94923c29d1..873318e365ba200ac72feb2bd39d90351ec8b240 100755 (executable)
@@ -687,6 +687,9 @@ class depgraph:
                                        "--getbinpkgonly" in self.myopts)
                self.args_keys = []
                self.global_updates = {}
+               self.pkg_node_map = {}
+               self.blocker_digraph = digraph()
+               self.blocker_parents = {}
 
        def create(self, mybigkey, myparent=None, addme=1, myuse=None,
                priority=digraph.HARD, rev_dep=False, arg=None):
@@ -701,15 +704,16 @@ class depgraph:
                #IUSE-aware emerge -> USE DEP aware depgraph
                #"no downgrade" emerge
                """
-
                jbigkey = " ".join(mybigkey) + " merge"
                if self.digraph.hasnode(jbigkey):
                        if addme and jbigkey != myparent:
                                # Refuse to make a node depend on itself so that the we don't
                                # don't create a bogus circular dependency in self.altlist().
                                if rev_dep and myparent:
+                                       self.pkg_node_map[myparent.split()[2]] = myparent
                                        self.digraph.addnode(myparent, jbigkey, priority=priority)
                                else:
+                                       self.pkg_node_map[mybigkey[2]] = jbigkey
                                        self.digraph.addnode(jbigkey, myparent, priority=priority)
                        return 1
                jbigkey = " ".join(mybigkey) + " nomerge"
@@ -718,8 +722,10 @@ class depgraph:
                        requested as a command line argument.  This can be solved by
                        checking all args prior to marking packages as nomerge"""
                        if rev_dep and myparent:
+                               self.pkg_node_map[myparent.split()[2]] = myparent
                                self.digraph.addnode(myparent, jbigkey, priority=priority)
                        else:
+                               self.pkg_node_map[mybigkey[2]] = jbigkey
                                self.digraph.addnode(jbigkey, myparent, priority=priority)
                        return 1
                
@@ -793,11 +799,14 @@ class depgraph:
                """ At this point, we have either hit a blocker and returned, found the package in the
                    depgraph already and returned, or we are here.  Whether we are merging or not; we must
                    add the package to the depgraph; so we do that here. """
+               jbigkey = " ".join(mybigkey)
                if rev_dep and myparent:
-                       self.digraph.addnode(myparent, " ".join(mybigkey),
+                       self.pkg_node_map[myparent.split()[2]] = myparent
+                       self.digraph.addnode(myparent, jbigkey,
                                priority=priority)
                else:
-                       self.digraph.addnode(" ".join(mybigkey), myparent,
+                       self.pkg_node_map[mybigkey[2]] = jbigkey
+                       self.digraph.addnode(jbigkey, myparent,
                                priority=priority)
                
                """ This section determines whether we go deeper into dependencies or not.
@@ -1120,12 +1129,10 @@ class depgraph:
                        selected_pkg = None
                        if x[0]=="!":
                                # if this package is myself, don't append it to block list.
-                               if "--debug" in self.myopts:
-                                       print "Myparent",myparent
-                               if (myparent):
-                                       if myparent.split()[2] in \
-                                               portdb.xmatch("match-all", x[1:]):
-                                               # myself, so exit.
+                               if myparent:
+                                       mydep = x[1:]
+                                       if mydep == portage.dep_getkey(mydep) and \
+                                               mydep == portage.dep_getkey(myparent.split()[2]):
                                                continue
                                # adding block
                                selected_pkg = ["blocks", myroot, x[1:], None]
@@ -1320,10 +1327,9 @@ class depgraph:
 
        def validate_blockers(self):
                """Remove any blockers from the digraph that do not match any of the
-               packages within the graph.  Blockers are only matched against the
-               final state of the graph.  Thus, it's possible that mutually blocking
-               packages will be installed simultaneously a some point(s) during the
-               transition from the initial to the final state."""
+               packages within the graph.  If necessary, create hard deps to ensure
+               correct merge order such that mutually blocking packages are never
+               installed simultaneously."""
 
                """ It's possible that some of the nodes haven't been added to the
                fakedb yet, so make sure they're all accounted for."""
@@ -1331,6 +1337,8 @@ class depgraph:
                        node_split = node.split()
                        mytype, myroot, mykey = node_split[0:3]
                        if mytype in self.pkg_tree_map:
+                               if node_split[3] == "nomerge":
+                                       continue
                                mydb = self.trees[myroot][self.pkg_tree_map[mytype]].dbapi
                                myslot = mydb.aux_get(mykey, ["SLOT"])[0]
                                self.mydbapi[myroot].cpv_inject(mykey, myslot=myslot)
@@ -1339,15 +1347,49 @@ class depgraph:
                                if node.split()[0] == "blocks"]
                for blocker in all_blockers:
                        mytype, myroot, mydep = blocker.split()
-                       """Prior to being added to the digraph, any blockers against
-                       old-style virtuals have been expanded to real packages via
-                       dep_virtual calls inside dep_check."""
+                       """ In case this block is unresolvable, save the parents for
+                       later output in self.display()."""
+                       self.blocker_parents[blocker] = self.digraph.parent_nodes(blocker)
                        if not self.mydbapi[myroot].match(mydep):
+                               vardb = self.trees[myroot]["vartree"].dbapi
+                               blocked_pkgs = vardb.match(mydep)
+                               if not blocked_pkgs:
+                                       self.digraph.remove(blocker)
+                                       continue
+                               """It may be possible to circumvent this block via correct
+                               ordering of upgrades.  If necessary, create hard deps to
+                               enforce correct merge order."""
+                               fakedb = self.mydbapi[myroot]
+                               new_pkgs = []
+                               for cpv in blocked_pkgs:
+                                       myslot = vardb.aux_get(cpv, ["SLOT"])[0]
+                                       myslot_atom = "%s:%s" % (portage.dep_getkey(cpv), myslot)
+                                       new_pkgs.append(
+                                               (myslot_atom, fakedb.match(myslot_atom)[0]))
+                               for parent in self.digraph.parent_nodes(blocker):
+                                       ptype, proot, pcpv, pstatus = parent.split()
+                                       pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi
+                                       pslot = pdbapi.aux_get(pcpv, ["SLOT"])[0]
+                                       pslot_atom = "%s:%s" % (portage.dep_getkey(pcpv), pslot)
+                                       for myslot_atom, pkg in new_pkgs:
+                                               if pslot_atom == myslot_atom:
+                                                       """A merge within a slot invalidates the block,
+                                                       so the order does not need to be enforced."""
+                                                       continue
+                                               # Enforce correct merge order with a hard dep.
+                                               node = self.pkg_node_map[pkg]
+                                               self.digraph.addnode(node, parent)
+                                               """Count references to this blocker so that it can be
+                                               invalidated after nodes referencing it have been merged."""
+                                               self.blocker_digraph.addnode(node, blocker)
                                self.digraph.remove(blocker)
 
        def altlist(self, reversed=False):
                mygraph=self.digraph.copy()
+               myblockers = self.blocker_digraph.copy()
                retlist=[]
+               circular_blocks = False
+               blocker_deps = None
                if reversed:
                        get_nodes = mygraph.root_nodes
                else:
@@ -1387,6 +1429,19 @@ class depgraph:
                                                else:
                                                        selected_nodes = None
 
+                       if not selected_nodes:
+                               if not myblockers.is_empty():
+                                       """A blocker couldn't be circumnavigated while keeping all
+                                       dependencies satisfied.  The user will have to resolve this
+                                       manually.  This is a panic condition and thus the order
+                                       doesn't really matter, so just pop a random node in order
+                                       to avoid a circular dependency panic if possible."""
+                                       if not circular_blocks:
+                                               circular_blocks = True
+                                               blocker_deps = myblockers.leaf_nodes()
+                                       if blocker_deps:
+                                               selected_nodes = [blocker_deps.pop()]
+
                        if not selected_nodes:
                                print "!!! Error: circular dependencies:"
                                print
@@ -1396,6 +1451,15 @@ class depgraph:
                        for node in selected_nodes:
                                retlist.append(node.split())
                                mygraph.remove(node)
+                               if not circular_blocks and myblockers.contains(node):
+                                       """This node may have invalidated one or more blockers."""
+                                       myblockers.remove(node)
+                                       for blocker in myblockers.root_nodes():
+                                               if not myblockers.child_nodes(blocker):
+                                                       myblockers.remove(blocker)
+
+               if not myblockers.is_empty():
+                       retlist.extend([node.split() for node in myblockers.root_nodes()])
 
                return retlist
 
@@ -1632,7 +1696,7 @@ class depgraph:
                                addl=""+red("B")+"  "+fetch+"  "
                                resolved = self.trees[x[1]]["vartree"].resolve_key(x[2])
                                print "["+x[0]+" "+addl+"]",red(resolved),
-                               block_parents = self.digraph.parent_nodes(" ".join(x))
+                               block_parents = self.blocker_parents[" ".join(x)]
                                block_parents = [pnode.split()[2] for pnode in block_parents]
                                block_parents = ", ".join(block_parents)
                                if resolved!=x[2]:
@@ -1642,17 +1706,26 @@ class depgraph:
                                        print bad("(is blocking %s)") % block_parents
                        else:
                                mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
-                               pkgsettings.setcpv(pkg_key, mydb=portdb)
-                               if pkg_key not in self.useFlags[myroot]:
-                                       if "ebuild" == pkg_type:
-                                               if "merge" == x[3] or not vartree.dbapi.cpv_exists(pkg_key):
-                                                       self.useFlags[myroot][pkg_key] = pkgsettings["USE"].split()
-                                               else:
-                                                       self.useFlags[myroot][pkg_key] = vartree.dbapi.aux_get(
-                                                               pkg_key, ["USE"])[0].split()
+                               binary_package = True
+                               if "ebuild" == pkg_type:
+                                       if "merge" == x[3] or \
+                                               not vartree.dbapi.cpv_exists(pkg_key):
+                                               """An ebuild "merge" node or a --onlydeps "nomerge"
+                                               node."""
+                                               binary_package = False
+                                               pkgsettings.setcpv(pkg_key, mydb=portdb)
+                                               if pkg_key not in self.useFlags[myroot]:
+                                                       self.useFlags[myroot][pkg_key] = \
+                                                               pkgsettings["USE"].split()
                                        else:
-                                               self.useFlags[myroot][pkg_key] = mydbapi.aux_get(
-                                                       pkg_key, ["USE"])[0].split()
+                                               # An ebuild "nomerge" node, so USE come from the vardb.
+                                               mydbapi = vartree.dbapi
+                               if pkg_key not in self.useFlags[myroot]:
+                                       """If this is a --resume then the USE flags need to be
+                                       fetched from the appropriate locations here."""
+                                       self.useFlags[myroot][pkg_key] = mydbapi.aux_get(
+                                               pkg_key, ["USE"])[0].split()
+
                                if "ebuild" == pkg_type and x[3] != "nomerge" and \
                                        "fetch" in portdb.aux_get(
                                        x[2], ["RESTRICT"])[0].split():
@@ -1703,10 +1776,11 @@ class depgraph:
                                                mydbapi.aux_get(pkg_key, ["IUSE"])[0].split()))
 
                                        forced_flags = set()
-                                       forced_flags.update(pkgsettings.useforce)
-                                       forced_flags.update(pkgsettings.puseforce)
-                                       forced_flags.update(pkgsettings.usemask)
-                                       forced_flags.update(pkgsettings.pusemask)
+                                       if not binary_package:
+                                               forced_flags.update(pkgsettings.useforce)
+                                               forced_flags.update(pkgsettings.puseforce)
+                                               forced_flags.update(pkgsettings.usemask)
+                                               forced_flags.update(pkgsettings.pusemask)
 
                                        cur_iuse = portage.unique_array(cur_iuse)
                                        cur_iuse.sort()
@@ -1854,7 +1928,13 @@ class depgraph:
                                                        myprint=myprint+myoldbest
                                                        myprint=myprint+darkgreen("to "+x[1])+" "+verboseadd
                                        else:
-                                               myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+darkgreen("to "+x[1])+" "+verboseadd
+                                               if x[3] == "nomerge":
+                                                       myprint = darkblue("[nomerge      ] ")
+                                               else:
+                                                       myprint = "[" + pkg_type + " " + addl + "] "
+                                               myprint += indent + darkgreen(pkg_key) + " " + \
+                                                       myoldbest + darkgreen("to " + myroot) + " " + \
+                                                       verboseadd
                                else:
                                        if "--columns" in self.myopts:
                                                if "--quiet" in self.myopts: