Merged from trunk 5995:6021
authorFabian Groffen <grobian@gentoo.org>
Mon, 26 Feb 2007 21:26:27 +0000 (21:26 -0000)
committerFabian Groffen <grobian@gentoo.org>
Mon, 26 Feb 2007 21:26:27 +0000 (21:26 -0000)
For bug #167450, optimize merge order by delaying the merge of root
nodes.

For bug #166880, always display the merge list (allowing --tree to be
obeyed in any case).

For bug #166880, always display the merge list header.

When calling tar, always exclud . in order to preserver
PORTAGE_WORKDIR_MODE.  Thanks to Brian Harring in bug #167544.

Don't exclude . since that excludes the entire contents of some tar
files.

For bug #166564, make a circular dependency panic more user friendly by
displaying the USE flags that are enabled on nodes that are part of
dependency cycles and display a note hinting that circular dependencies
can often be avoided by temporarily disabling USE flags.

Automatically enable --tree mode when displaying nodes with circular
deps.

For bug #167450, optimize leaf node selection by ordering nodes from
highest to lowest overall reference count.

Make digraph._merge_order_bias() operate on a single digraph that's
passed in.

Optimize order for --tree display of circular dependencies.

As requested by vapier, don't show the merge list in --quiet mode unless
it's explicitly requested via --ask or --pretend.

For bug #167795, try avoid the population routine when possible, so that
FEATURES=buildpkg doesn't always force population.

Raise a CommandNotFound exception when necessary, to ease
troubleshooting.  Thanks to marienz for reporting.

svn path=/main/branches/prefix/; revision=6080

bin/ebuild.sh
pym/emerge/__init__.py
pym/portage/dbapi/bintree.py
pym/portage/process.py

index e8361538b9e56f3f87ebcbad16ef5e00c93d063a..620e47e0490174b2d189c466bdf23a4502e7a029 100755 (executable)
@@ -462,7 +462,7 @@ unpack() {
        local x
        local y
        local myfail
-
+       local tar_opts=""
        [ -z "$*" ] && die "Nothing passed to the 'unpack' command"
 
        for x in "$@"; do
@@ -483,13 +483,13 @@ unpack() {
                myfail="failure unpacking ${x}"
                case "${x##*.}" in
                        tar)
-                               tar xof "${srcdir}${x}" || die "$myfail"
+                               tar xof "${srcdir}${x}" ${tar_opts} || die "$myfail"
                                ;;
                        tgz)
-                               tar xozf "${srcdir}${x}" || die "$myfail"
+                               tar xozf "${srcdir}${x}" ${tar_opts} || die "$myfail"
                                ;;
                        tbz|tbz2)
-                               bzip2 -dc "${srcdir}${x}" | tar xof -
+                               bzip2 -dc "${srcdir}${x}" | tar xof - ${tar_opts}
                                assert "$myfail"
                                ;;
                        ZIP|zip|jar)
@@ -497,14 +497,14 @@ unpack() {
                                ;;
                        gz|Z|z)
                                if [ "${y}" == "tar" ]; then
-                                       tar zoxf "${srcdir}${x}" || die "$myfail"
+                                       tar zoxf "${srcdir}${x}" ${tar_opts} || die "$myfail"
                                else
                                        gzip -dc "${srcdir}${x}" > ${x%.*} || die "$myfail"
                                fi
                                ;;
                        bz2|bz)
                                if [ "${y}" == "tar" ]; then
-                                       bzip2 -dc "${srcdir}${x}" | tar xof -
+                                       bzip2 -dc "${srcdir}${x}" | tar xof - ${tar_opts}
                                        assert "$myfail"
                                else
                                        bzip2 -dc "${srcdir}${x}" > ${x%.*} || die "$myfail"
index 9709765050707c0fc4f97abd3ce9d8decec7c89c..d70a788c26dffeb23e8687e6a029b7db477dc4e8 100644 (file)
@@ -1972,6 +1972,16 @@ class depgraph:
                                break
                return acceptable
 
+       def _merge_order_bias(self, mygraph):
+               """Order nodes from highest to lowest overall reference count for
+               optimal leaf node selection."""
+               node_info = {}
+               for node in mygraph.order:
+                       node_info[node] = len(mygraph.parent_nodes(node))
+               def cmp_merge_preference(node1, node2):
+                       return node_info[node2] - node_info[node1]
+               mygraph.order.sort(cmp_merge_preference)
+
        def altlist(self, reversed=False):
                if reversed in self._altlist_cache:
                        return self._altlist_cache[reversed][:]
@@ -1981,6 +1991,7 @@ class depgraph:
                        self._altlist_cache[reversed] = retlist[:]
                        return retlist
                mygraph=self.digraph.copy()
+               self._merge_order_bias(mygraph)
                myblockers = self.blocker_digraph.copy()
                retlist=[]
                circular_blocks = False
@@ -2026,8 +2037,18 @@ class depgraph:
                                                # output, so it's disabled in reversed mode.
                                                selected_nodes = nodes
                                        else:
-                                               # Only pop one node for optimal merge order.
-                                               selected_nodes = [nodes[0]]
+                                               # For optimal merge order:
+                                               #  * Only pop one node.
+                                               #  * Removing a root node (node without a parent)
+                                               #    will not produce a leaf node, so avoid it.
+                                               for node in nodes:
+                                                       if mygraph.parent_nodes(node):
+                                                               # found a non-root node
+                                                               selected_nodes = [node]
+                                                               break
+                                               if not selected_nodes:
+                                                       # settle for a root node
+                                                       selected_nodes = [nodes[0]]
                                else:
                                        """Recursively gather a group of nodes that RDEPEND on
                                        eachother.  This ensures that they are merged as a group
@@ -2067,14 +2088,10 @@ class depgraph:
                                                selected_nodes = [blocker_deps.pop()]
 
                        if not selected_nodes:
-                               if reversed:
-                                       """The circular deps ouput should have less noise when
-                                       altlist is not in reversed mode."""
-                                       self.altlist()
-                               print "!!! Error: circular dependencies:"
-                               print
-                               # Reduce the noise level to a minimum via elimination of root
-                               # nodes.
+                               # No leaf nodes are available, so we have a circular
+                               # dependency panic situation.  Reduce the noise level to a
+                               # minimum via repeated elimination of root nodes since they
+                               # have no parents and thus can not be part of a cycle.
                                while True:
                                        root_nodes = mygraph.root_nodes(
                                                ignore_priority=DepPriority.SOFT)
@@ -2082,7 +2099,30 @@ class depgraph:
                                                break
                                        for node in root_nodes:
                                                mygraph.remove(node)
+                               # Display the USE flags that are enabled on nodes that are part
+                               # of dependency cycles in case that helps the user decide to
+                               # disable some of them.
+                               display_order = []
+                               tempgraph = mygraph.copy()
+                               while not tempgraph.empty():
+                                       nodes = tempgraph.leaf_nodes()
+                                       if not nodes:
+                                               node = tempgraph.order[0]
+                                       else:
+                                               node = nodes[0]
+                                       display_order.append(list(node))
+                                       tempgraph.remove(node)
+                               display_order.reverse()
+                               self.myopts.pop("--quiet", None)
+                               self.myopts.pop("--verbose", None)
+                               self.myopts["--tree"] = True
+                               self.display(display_order)
+                               print "!!! Error: circular dependencies:"
+                               print
                                mygraph.debug_print()
+                               print
+                               print "!!! Note that circular dependencies can often be avoided by temporarily"
+                               print "!!! disabling USE flags that trigger optional dependencies."
                                sys.exit(1)
 
                        for node in selected_nodes:
@@ -4683,7 +4723,7 @@ def action_build(settings, trees, mtimedb,
        myopts, myaction, myfiles, spinner):
        ldpath_mtimes = mtimedb["ldpath"]
        favorites=[]
-       if ("--ask" in myopts or "--pretend" in myopts) and not "--quiet" in myopts:
+       if "--quiet" not in myopts:
                action = ""
                if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
                        action = "fetched"
@@ -4772,7 +4812,8 @@ def action_build(settings, trees, mtimedb,
                        sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
                        sys.exit(1)
 
-       if "--ask" in myopts:
+       if "--pretend" not in myopts and \
+               not ("--quiet" in myopts and "--ask" not in myopts):
                if "--resume" in myopts:
                        validate_merge_list(trees, mtimedb["resume"]["mergelist"])
                        mymergelist = mtimedb["resume"]["mergelist"]
@@ -4815,13 +4856,13 @@ def action_build(settings, trees, mtimedb,
                        else:
                                prompt="Would you like to merge these packages?"
                print
-               if userquery(prompt)=="No":
+               if "--ask" in myopts and userquery(prompt) == "No":
                        print
                        print "Quitting."
                        print
                        sys.exit(0)
                # Don't ask again (e.g. when auto-cleaning packages after merge)
-               del myopts["--ask"]
+               myopts.pop("--ask", None)
 
        if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
                if ("--resume" in myopts):
index a833f033c09a6753e9877af58a5fb42b2956e334..4a0c70e18f4072e33ea3213dd754dacc452c1080 100644 (file)
@@ -285,6 +285,17 @@ class binarytree(object):
                use for a given cpv.  If a collision will occur with an existing
                package from another category, the existing package will be bumped to
                ${PKGDIR}/${CATEGORY}/${PF}.tbz2 so that both can coexist."""
+               if not self.populated:
+                       # Try to avoid the population routine when possible, so that
+                       # FEATURES=buildpkg doesn't always force population.
+                       mycat, mypkg = catsplit(cpv)
+                       myfile = mypkg + ".tbz2"
+                       full_path = os.path.join(self.pkgdir, "All", myfile)
+                       if not os.path.exists(full_path):
+                               return
+                       tbz2_cat = portage.xpak.tbz2(full_path).getfile("CATEGORY")
+                       if tbz2_cat and tbz2_cat.strip() == mycat:
+                               return
                full_path = self.getname(cpv)
                if "All" == full_path.split(os.path.sep)[-2]:
                        return
index 20b1d705c41b9c5fd698568d9b8b25f3d3d35db2..dfc106e6bdd4705afdc6afe2689d064458ef1087 100644 (file)
@@ -9,7 +9,7 @@ import portage.data
 
 from portage.util import dump_traceback
 from portage.const import BASH_BINARY, SANDBOX_BINARY
-
+from portage.exception import CommandNotFound
 
 try:
        import resource
@@ -157,7 +157,7 @@ def spawn(mycommand, env={}, opt_name=None, fd_pipes=None, returnpid=False,
            or not os.access(binary, os.X_OK)):
                binary = path_lookup and find_binary(binary) or None
                if not binary:
-                       return -1
+                       raise CommandNotFound(mycommand[0])
 
        # If we haven't been told what file descriptors to use
        # default to propogating our stdin, stdout and stderr.