From 647133120bf44c2706f30e1a3e45420c888d56e5 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Mon, 26 Feb 2007 21:26:27 +0000 Subject: [PATCH] Merged from trunk 5995:6021 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 | 12 +++---- pym/emerge/__init__.py | 69 ++++++++++++++++++++++++++++-------- pym/portage/dbapi/bintree.py | 11 ++++++ pym/portage/process.py | 4 +-- 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/bin/ebuild.sh b/bin/ebuild.sh index e8361538b..620e47e04 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -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" diff --git a/pym/emerge/__init__.py b/pym/emerge/__init__.py index 970976505..d70a788c2 100644 --- a/pym/emerge/__init__.py +++ b/pym/emerge/__init__.py @@ -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): diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py index a833f033c..4a0c70e18 100644 --- a/pym/portage/dbapi/bintree.py +++ b/pym/portage/dbapi/bintree.py @@ -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 diff --git a/pym/portage/process.py b/pym/portage/process.py index 20b1d705c..dfc106e6b 100644 --- a/pym/portage/process.py +++ b/pym/portage/process.py @@ -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. -- 2.26.2