Merged from trunk -r13804:13812
authorFabian Groffen <grobian@gentoo.org>
Sat, 11 Jul 2009 13:02:15 +0000 (13:02 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 11 Jul 2009 13:02:15 +0000 (13:02 -0000)
   | 13805   | Bug #276957 - Fix dropped "in graph" choice for runtime deps |
   | zmedico | inside dep_zapdeps.                                          |

   | 13806   | Fix --selective so it works.                                 |
   | zmedico |                                                              |

   | 13807   | Document the --selective option.                             |
   | zmedico |                                                              |

   | 13808   | Add a --debug warning message inside _add_pkg in case a      |
   | zmedico | potentially infinite backtracking loop is detected (it       |
   |         | should never happen).                                        |

   | 13809   | Use a dict for depgraph params, so we can use it to store    |
   | zmedico | key/value pairs and fix the depgraph so it doesn't use       |
   |         | emerge options directly.                                     |

   | 13810   | Make -j argument handling more generic, so it's easy to add  |
   | zmedico | similar arguments (planning to add support for integer       |
   |         | -D/--deep arguments).                                        |

   | 13811   | Tweak arguments for <python-2.6 compat.                      |
   | zmedico |                                                              |

   | 13812   | Allow --deep to take an optional integer parameter, to       |
   | zmedico | specify how deep it should go. Also make --update so it no   |
   |         | longer implies the equivalent of --deep=1. To get the old    |
   |         | --update behavior, use --update --deep=1.                    |

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

man/emerge.1
pym/_emerge/create_depgraph_params.py
pym/_emerge/depgraph.py
pym/_emerge/help.py
pym/_emerge/main.py
pym/portage/__init__.py

index 852116d183e2b216e57d351d057fdae3e9ee748c..4e25085bf0b2cd3fcc0ae4726d2f784937fb0969 100644 (file)
@@ -225,8 +225,8 @@ use \fB\-\-depclean\fR or \fB\-\-prune\fR.
 .TP
 .BR "\-\-update " (\fB\-u\fR)
 Updates packages to the best version available, which may not always be the 
-highest version number due to masking for testing and development.  This will 
-also update direct dependencies which may not be what you want.  Package atoms
+highest version number due to masking for testing and development.
+Package atoms
 specified on the command line are greedy, meaning that unspecific atoms may
 match multiple installed versions of slotted packages.
 .TP
@@ -301,7 +301,7 @@ mode the bash build environment will run with the \-x option, causing
 it to output verbose debugging information to stdout.  This also enables
 a plethora of other output (mostly dependency resolution messages).
 .TP
-.BR "\-\-deep " (\fB\-D\fR)
+.BR "\-\-deep [DEPTH] " (\fB\-D\fR)
 This flag forces
 \fBemerge\fR to consider the entire dependency tree of packages,
 instead of checking only the immediate dependencies of the packages.
@@ -446,6 +446,10 @@ be enabled under normal circumstances. For currently supported
 \fBDEPEND\fR variable. However, behavior may change for new
 \fBEAPI\fRs when related extensions are added in the future.
 .TP
+.BR "\-\-selective"
+This is similar to the \fB\-\-noreplace\fR option, except that it
+does not take precedence over options such as \fB\-\-newuse\fR.
+.TP
 .BR "\-\-skipfirst"
 This option is only valid when used with \fB\-\-resume\fR.  It removes the 
 first package in the resume list. Dependencies are recalculated for
index 5baad8004c1b2bff0dab72b9740bc05b8d3f082e..9381fb9554be0173fd042753e39200f86deee80b 100644 (file)
@@ -12,26 +12,27 @@ def create_depgraph_params(myopts, myaction):
        # empty:     pretend nothing is merged
        # complete:  completely account for all known dependencies
        # remove:    build graph for use in removing packages
-       myparams = set(["recurse"])
+       myparams = {"recurse" : True}
 
        if myaction == "remove":
-               myparams.add("remove")
-               myparams.add("complete")
+               myparams["remove"] = True
+               myparams["complete"] = True
                return myparams
 
        if "--update" in myopts or \
                "--newuse" in myopts or \
                "--reinstall" in myopts or \
-               "--noreplace" in myopts:
-               myparams.add("selective")
+               "--noreplace" in myopts or \
+               "--selective" in myopts:
+               myparams["selective"] = True
        if "--emptytree" in myopts:
-               myparams.add("empty")
-               myparams.discard("selective")
+               myparams["empty"] = True
+               myparams.pop("selective", None)
        if "--nodeps" in myopts:
-               myparams.discard("recurse")
+               myparams.pop("recurse", None)
        if "--deep" in myopts:
-               myparams.add("deep")
+               myparams["deep"] = myopts["--deep"]
        if "--complete-graph" in myopts:
-               myparams.add("complete")
+               myparams["complete"] = True
        return myparams
 
index a000e900a1fe7058e6fa7fde1d337a3ab23ecf0e..b53fd98b6b31bc1c4b60764597ce353087d87caf 100644 (file)
@@ -613,8 +613,8 @@ class depgraph(object):
                buildpkgonly = "--buildpkgonly" in self._frozen_config.myopts
                nodeps = "--nodeps" in self._frozen_config.myopts
                empty = "empty" in self._dynamic_config.myparams
-               deep = "deep" in self._dynamic_config.myparams
-               update = "--update" in self._frozen_config.myopts and dep.depth <= 1
+               deep = self._dynamic_config.myparams.get("deep", 0)
+               recurse = empty or deep is True or dep.depth <= deep
                if dep.blocker:
                        if not buildpkgonly and \
                                not nodeps and \
@@ -650,7 +650,7 @@ class depgraph(object):
                # available for optimization of merge order.
                if dep.priority.satisfied and \
                        not dep_pkg.installed and \
-                       not (existing_node or empty or deep or update):
+                       not (existing_node or recurse):
                        myarg = None
                        if dep.root == self._frozen_config.target_root:
                                try:
@@ -760,7 +760,19 @@ class depgraph(object):
                                        return 1
                                else:
                                        # A slot conflict has occurred. 
+                                       # The existing node should not already be in
+                                       # runtime_pkg_mask, since that would trigger an
+                                       # infinite backtracking loop.
                                        if self._dynamic_config._allow_backtracking and \
+                                               existing_node in \
+                                               self._dynamic_config._runtime_pkg_mask:
+                                               if "--debug" in self._frozen_config.myopts:
+                                                       writemsg(
+                                                               "!!! backtracking loop detected: %s %s\n" % \
+                                                               (existing_node,
+                                                               self._dynamic_config._runtime_pkg_mask[
+                                                               existing_node]), noiselevel=-1)
+                                       elif self._dynamic_config._allow_backtracking and \
                                                not self._accept_blocker_conflicts():
                                                self._add_slot_conflict(pkg)
                                                if dep.atom is not None and dep.parent is not None:
@@ -847,18 +859,20 @@ class depgraph(object):
                    emerge --deep <pkgspec>; we need to recursively check dependencies of pkgspec
                    If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies.
                """
+               if arg_atoms:
+                       depth = 0
+               pkg.depth = depth
+               deep = self._dynamic_config.myparams.get("deep", 0)
+               empty = "empty" in self._dynamic_config.myparams
+               recurse = empty or deep is True or depth + 1 <= deep
                dep_stack = self._dynamic_config._dep_stack
                if "recurse" not in self._dynamic_config.myparams:
                        return 1
-               elif pkg.installed and \
-                       "deep" not in self._dynamic_config.myparams:
+               elif pkg.installed and not recurse:
                        dep_stack = self._dynamic_config._ignored_deps
 
                self._frozen_config.spinner.update()
 
-               if arg_atoms:
-                       depth = 0
-               pkg.depth = depth
                if not previously_added:
                        dep_stack.append(pkg)
                return 1
@@ -2286,9 +2300,9 @@ class depgraph(object):
                # accounted for.
                self._select_atoms = self._select_atoms_from_graph
                self._select_package = self._select_pkg_from_graph
-               already_deep = "deep" in self._dynamic_config.myparams
+               already_deep = self._dynamic_config.myparams.get("deep") is True
                if not already_deep:
-                       self._dynamic_config.myparams.add("deep")
+                       self._dynamic_config.myparams["deep"] = True
 
                for root in self._frozen_config.roots:
                        required_set_names = self._frozen_config._required_set_names.copy()
@@ -3374,7 +3388,7 @@ class depgraph(object):
                if have_uninstall_task and \
                        not complete and \
                        not unsolvable_blockers:
-                       self._dynamic_config.myparams.add("complete")
+                       self._dynamic_config.myparams["complete"] = True
                        raise self._serialize_tasks_retry("")
 
                if unsolvable_blockers and \
@@ -4513,7 +4527,7 @@ class depgraph(object):
                        self._dynamic_config._scheduler_graph = self._dynamic_config.digraph
                else:
                        self._select_package = self._select_pkg_from_graph
-                       self._dynamic_config.myparams.add("selective")
+                       self._dynamic_config.myparams["selective"] = True
                        # Always traverse deep dependencies in order to account for
                        # potentially unsatisfied dependencies of installed packages.
                        # This is necessary for correct --keep-going or --resume operation
@@ -4526,7 +4540,7 @@ class depgraph(object):
                        # deep depenedencies of a scheduled build, that build needs to
                        # be cancelled. In order for this type of situation to be
                        # recognized, deep traversal of dependencies is required.
-                       self._dynamic_config.myparams.add("deep")
+                       self._dynamic_config.myparams["deep"] = True
 
                        favorites = resume_data.get("favorites")
                        args_set = self._dynamic_config._sets["args"]
index f78c2e0e0f1887f39987e1082d7088d845692585..3938866985c9ae77d2d9aa3f5fdfd1115f3917d7 100644 (file)
@@ -220,8 +220,7 @@ def help(myopts, havecolor=1):
                print "       "+green("--update")+" ("+green("-u")+" short option)"
                print "              Updates packages to the best version available, which may not"
                print "              always be the highest version number due to masking for testing"
-               print "              and development. This will also update direct dependencies which"
-               print "              may not be what you want. Package atoms specified on the command"
+               print "              and development. Package atoms specified on the command"
                print "              line are greedy, meaning that unspecific atoms may match multiple"
                print "              installed versions of slotted packages."
                print
@@ -314,7 +313,8 @@ def help(myopts, havecolor=1):
                print "              --debug is great for finding bash syntax errors as providing"
                print "              very verbose information about the dependency and build process."
                print
-               print "       "+green("--deep")+" ("+green("-D")+" short option)"
+               print "       "+green("--deep") + " " + turquoise("[DEPTH]") + \
+                       " (" + green("-D") + " short option)"
                print "              This flag forces emerge to consider the entire dependency tree of"
                print "              packages, instead of checking only the immediate dependencies of"
                print "              the packages. As an example, this catches updates in libraries"
@@ -467,6 +467,12 @@ def help(myopts, havecolor=1):
                for line in wrap(desc, desc_width):
                        print desc_indent + line
                print
+               print "       " + green("--selective")
+               desc = "This is similar to the --noreplace option, except that it " + \
+                       "does not take precedence over options such as --newuse."
+               for line in wrap(desc, desc_width):
+                       print desc_indent + line
+               print
                print "       "+green("--skipfirst")
                desc = "This option is only valid when " + \
                        "used with --resume.  It removes the " + \
index 1a4ee877d564ab994ad45f17e1280d02e169ba47..8e0702c7d308a18858295fee331affd437f0b688 100644 (file)
@@ -62,7 +62,7 @@ options=[
 "--buildpkg",     "--buildpkgonly",
 "--changelog",    "--columns",
 "--complete-graph",
-"--debug",        "--deep",
+"--debug",
 "--digest",
 "--emptytree",
 "--fetchonly",    "--fetch-all-uri",
@@ -88,7 +88,7 @@ shortmapping={
 "a":"--ask",
 "b":"--buildpkg",  "B":"--buildpkgonly",
 "c":"--clean",     "C":"--unmerge",
-"d":"--debug",     "D":"--deep",
+"d":"--debug",
 "e":"--emptytree",
 "f":"--fetchonly", "F":"--fetch-all-uri",
 "g":"--getbinpkg", "G":"--getbinpkgonly",
@@ -383,13 +383,31 @@ def insert_optional_args(args):
        this feature natively.
        """
 
+       class valid_integers(object):
+               def __contains__(self, s):
+                       try:
+                               int(s)
+                       except (ValueError, OverflowError):
+                               return False
+                       return True
+
+       valid_integers = valid_integers()
+
        new_args = []
-       jobs_opts = ("-j", "--jobs")
+
        default_arg_opts = {
+               '--deep'       : valid_integers,
                '--deselect'   : ('n',),
                '--binpkg-respect-use'   : ('n', 'y',),
+               '--jobs'       : valid_integers,
                '--root-deps'  : ('rdeps',),
        }
+
+       short_arg_opts = {
+               'D' : valid_integers,
+               'j' : valid_integers,
+       }
+
        arg_stack = args[:]
        arg_stack.reverse()
        while arg_stack:
@@ -405,42 +423,54 @@ def insert_optional_args(args):
                                new_args.append('True')
                        continue
 
-               short_job_opt = bool("j" in arg and arg[:1] == "-" and arg[:2] != "--")
-               if not (short_job_opt or arg in jobs_opts):
+               if arg[:1] != "-" or arg[:2] == "--":
                        new_args.append(arg)
                        continue
 
+               match = None
+               for k, arg_choices in short_arg_opts.iteritems():
+                       if k in arg:
+                               match = k
+                               break
+
+               if match is None:
+                       new_args.append(arg)
+                       continue
+
+               if len(arg) == 2:
+                       new_args.append(arg)
+                       if arg_stack and arg_stack[-1] in arg_choices:
+                               new_args.append(arg_stack.pop())
+                       else:
+                               # insert default argument
+                               new_args.append('True')
+                       continue
+
                # Insert an empty placeholder in order to
                # satisfy the requirements of optparse.
 
-               new_args.append("--jobs")
-               job_count = None
+               new_args.append("-" + match)
+               opt_arg = None
                saved_opts = None
-               if short_job_opt and len(arg) > 2:
-                       if arg[:2] == "-j":
-                               try:
-                                       job_count = int(arg[2:])
-                               except ValueError:
-                                       saved_opts = arg[2:]
-                       else:
-                               job_count = "True"
-                               saved_opts = arg[1:].replace("j", "")
 
-               if job_count is None and arg_stack:
-                       try:
-                               job_count = int(arg_stack[-1])
-                       except ValueError:
-                               pass
+               if arg[1:2] == match:
+                       if arg[2:] in arg_choices:
+                               opt_arg = arg[2:]
                        else:
-                               # Discard the job count from the stack
-                               # since we're consuming it here.
-                               arg_stack.pop()
+                               saved_opts = arg[2:]
+                               opt_arg = "True"
+               else:
+                       saved_opts = arg[1:].replace(match, "")
+                       opt_arg = "True"
 
-               if job_count is None:
-                       # unlimited number of jobs
+               if opt_arg is None and arg_stack and \
+                       arg_stack[-1] in arg_choices:
+                       opt_arg = arg_stack.pop()
+
+               if opt_arg is None:
                        new_args.append("True")
                else:
-                       new_args.append(str(job_count))
+                       new_args.append(opt_arg)
 
                if saved_opts is not None:
                        new_args.append("-" + saved_opts)
@@ -473,6 +503,18 @@ def parse_opts(tmpcmdline, silent=False):
                        "choices":("y", "n")
                },
 
+               "--deep": {
+
+                       "shortopt" : "-D",
+
+                       "help"   : "Specifies how deep to recurse into dependencies " + \
+                               "of packages given as arguments. If no argument is given, " + \
+                               "depth is unlimited. Default behavior is to skip " + \
+                               "dependencies of installed packages.",
+
+                       "action" : "store"
+               },
+
                "--deselect": {
                        "help"    : "remove atoms from the world file",
                        "type"    : "choice",
@@ -481,6 +523,8 @@ def parse_opts(tmpcmdline, silent=False):
 
                "--jobs": {
 
+                       "shortopt" : "-j",
+
                        "help"   : "Specifies the number of packages to build " + \
                                "simultaneously.",
 
@@ -545,8 +589,12 @@ def parse_opts(tmpcmdline, silent=False):
                        dest=myopt.lstrip("--").replace("-", "_"), default=False)
 
        for myopt, kwargs in argument_options.iteritems():
-               parser.add_option(myopt,
-                       dest=myopt.lstrip("--").replace("-", "_"), **kwargs)
+               shortopt = kwargs.pop("shortopt", None)
+               args = [myopt]
+               if shortopt is not None:
+                       args.append(shortopt)
+               parser.add_option(dest=myopt.lstrip("--").replace("-", "_"),
+                       *args, **kwargs)
 
        tmpcmdline = insert_optional_args(tmpcmdline)
 
@@ -563,6 +611,24 @@ def parse_opts(tmpcmdline, silent=False):
        if myoptions.root_deps == "True":
                myoptions.root_deps = True
 
+       if myoptions.deep is not None:
+               deep = None
+               if myoptions.deep == "True":
+                       deep = True
+               else:
+                       try:
+                               deep = int(myoptions.deep)
+                       except (OverflowError, ValueError):
+                               deep = -1
+
+               if deep is not True and deep < 0:
+                       deep = None
+                       if not silent:
+                               writemsg("!!! Invalid --deep parameter: '%s'\n" % \
+                                       (myoptions.deep,), noiselevel=-1)
+
+               myoptions.deep = deep
+
        if myoptions.jobs:
                jobs = None
                if myoptions.jobs == "True":
index 85c5312e0589e9959b53724cba1dfebac697e6be..1c0a706f11dd600871d89bc3593addf4d05ef4f0 100644 (file)
@@ -7229,6 +7229,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
                                                        preferred_in_graph.append(this_choice)
                                                else:
                                                        other.append(this_choice)
+                                       else:
+                                               preferred_in_graph.append(this_choice)
                                else:
                                        preferred_non_installed.append(this_choice)
                else: