emerge: add 3 new options similar to --exclude
authorDavid James <davidjames@google.com>
Wed, 27 Apr 2011 22:07:12 +0000 (15:07 -0700)
committerZac Medico <zmedico@gentoo.org>
Wed, 27 Apr 2011 22:07:12 +0000 (15:07 -0700)
Add --nousepkg-atoms, --useoldpkg-atoms, and --reinstall-atoms flag
to Portage

reinstall-atoms accepts a space separated list of package names or
slot atoms. Emerge will treat matching packages as if they are not
installed, and reinstall them if necessary.

useoldpkg-atoms accepts a space separated list of package names or
slot atoms. Emerge will prefer matching binary packages over newer
unbuilt packages. This is useful in case you want to request that a
particular package won't be rebuilt from source.

nousepkg-atoms accepts a space separated list of package names or
slot atoms. Emerge will ignore matching binary packages.

Change-Id: I0d73039c6a4cd63695b28ffc80215628e0e05c95

BUG=chromium-os:12507 TEST=Try out the flag

Review URL: http://codereview.chromium.org/6577024

man/emerge.1
pym/_emerge/depgraph.py
pym/_emerge/main.py

index 2693b6753de5da5793904f31ef5c40cf3a3b5ab8..67f3e4796befc4e278fc3075a8c089120d8b47de 100644 (file)
@@ -479,6 +479,10 @@ may have changed.
 Disables the spinner for the session.  The spinner is active when the
 terminal device is determined to be a TTY.  This flag disables it regardless.
 .TP
+.BR "\-\-nousepkg\-atoms " ATOMS
+A space separated list of package names or slot atoms. Emerge will ignore
+matching binary packages.
+.TP
 .BR "\-\-oneshot " (\fB\-1\fR)
 Emerge as normal, but do not add the packages to the world file
 for later updating.
@@ -549,6 +553,11 @@ changed since installation.  Unlike \fB\-\-newuse\fR, this option does
 not trigger reinstallation when flags that the user has not
 enabled are added or removed.
 .TP
+.BR "\-\-reinstall\-atoms " ATOMS
+A space separated list of package names or slot atoms. Emerge will treat
+matching packages as if they are not installed, and reinstall them if
+necessary.
+.TP
 .BR \-\-root=DIR
 Set the \fBROOT\fR environment variable.
 .TP
@@ -606,6 +615,10 @@ atoms may match multiple versions of slotted packages.
 Use unbuilt ebuild metadata for visibility
 checks on built packages.
 .TP
+.BR "\-\-useoldpkg\-atoms " ATOMS
+A space separated list of package names or slot atoms. Emerge will prefer
+matching binary packages over newer unbuilt packages.
+.TP
 .BR "\-\-usepkg [ y | n ] (\-k short option)"
 Tells emerge to use binary packages (from $PKGDIR) if they are available, thus 
 possibly avoiding some time\-consuming compiles.  This option is useful for CD 
index a0a4622eeb67fc5f7bdc278854322548ed2c980b..84e7d24f162b6c73b87a12f200ff9f05eda1d0b6 100644 (file)
@@ -70,6 +70,16 @@ class _scheduler_graph_config(object):
                self.graph = graph
                self.mergelist = mergelist
 
+def _wildcard_set(atoms):
+       pkgs = InternalPackageSet(allow_wildcard=True)
+       for x in atoms:
+               try:
+                       x = Atom(x, allow_wildcard=True)
+               except portage.exception.InvalidAtom:
+                       x = Atom("*/" + x, allow_wildcard=True)
+               pkgs.add(x)
+       return pkgs
+
 class _frozen_depgraph_config(object):
 
        def __init__(self, settings, trees, myopts, spinner):
@@ -109,13 +119,14 @@ class _frozen_depgraph_config(object):
 
                self._required_set_names = set(["world"])
 
-               self.excluded_pkgs = InternalPackageSet(allow_wildcard=True)
-               for x in ' '.join(myopts.get("--exclude", [])).split():
-                       try:
-                               x = Atom(x, allow_wildcard=True)
-                       except portage.exception.InvalidAtom:
-                               x = Atom("*/" + x, allow_wildcard=True)
-                       self.excluded_pkgs.add(x)
+               atoms = ' '.join(myopts.get("--exclude", [])).split()
+               self.excluded_pkgs = _wildcard_set(atoms)
+               atoms = ' '.join(myopts.get("--reinstall-atoms", [])).split()
+               self.reinstall_atoms = _wildcard_set(atoms)
+               atoms = ' '.join(myopts.get("--nousepkg-atoms", [])).split()
+               self.nousepkg_atoms = _wildcard_set(atoms)
+               atoms = ' '.join(myopts.get("--useoldpkg-atoms", [])).split()
+               self.useoldpkg_atoms = _wildcard_set(atoms)
 
 class _depgraph_sets(object):
        def __init__(self):
@@ -1237,6 +1248,7 @@ class depgraph(object):
                vardb = root_config.trees["vartree"].dbapi
                traversed_virt_pkgs = set()
 
+               reinstall_atoms = self._frozen_config.reinstall_atoms
                for atom, child in self._minimize_children(
                        pkg, dep_priority, root_config, selected_atoms[pkg]):
 
@@ -1254,7 +1266,9 @@ class depgraph(object):
 
                        mypriority = dep_priority.copy()
                        if not atom.blocker:
-                               inst_pkgs = vardb.match_pkgs(atom)
+                               inst_pkgs = [inst_pkg for inst_pkg in vardb.match_pkgs(atom)
+                                       if not reinstall_atoms.findAtomForPackage(inst_pkg,
+                                                       modified_use=self._pkg_use_enabled(inst_pkg))]
                                if inst_pkgs:
                                        for inst_pkg in inst_pkgs:
                                                if self._pkg_visibility_check(inst_pkg):
@@ -1344,7 +1358,9 @@ class depgraph(object):
                                # This is a GLEP 37 virtual, so its deps are all runtime.
                                mypriority = self._priority(runtime=True)
                                if not atom.blocker:
-                                       inst_pkgs = vardb.match_pkgs(atom)
+                                       inst_pkgs = [inst_pkg for inst_pkg in vardb.match_pkgs(atom)
+                                               if not reinstall_atoms.findAtomForPackage(inst_pkg,
+                                                               modified_use=self._pkg_use_enabled(inst_pkg))]
                                        if inst_pkgs:
                                                for inst_pkg in inst_pkgs:
                                                        if self._pkg_visibility_check(inst_pkg):
@@ -3161,6 +3177,10 @@ class depgraph(object):
                dont_miss_updates = "--update" in self._frozen_config.myopts
                use_ebuild_visibility = self._frozen_config.myopts.get(
                        '--use-ebuild-visibility', 'n') != 'n'
+               reinstall_atoms = self._frozen_config.reinstall_atoms
+               nousepkg_atoms = self._frozen_config.nousepkg_atoms
+               useoldpkg_atoms = self._frozen_config.useoldpkg_atoms
+               matched_oldpkg = []
                # Behavior of the "selective" parameter depends on
                # whether or not a package matches an argument atom.
                # If an installed package provides an old-style
@@ -3200,7 +3220,14 @@ class depgraph(object):
                                                        modified_use=self._pkg_use_enabled(pkg)):
                                                continue
 
-                                       if packages_with_invalid_use_config and \
+                                       if built and not installed and nousepkg_atoms.findAtomForPackage(pkg, \
+                                               modified_use=self._pkg_use_enabled(pkg)):
+                                               break
+
+                                       useoldpkg = useoldpkg_atoms.findAtomForPackage(pkg, \
+                                               modified_use=self._pkg_use_enabled(pkg))
+
+                                       if packages_with_invalid_use_config and (not built or not useoldpkg) and \
                                                (not pkg.installed or dont_miss_updates):
                                                # Check if a higher version was rejected due to user
                                                # USE configuration. The packages_with_invalid_use_config
@@ -3282,7 +3309,7 @@ class depgraph(object):
                                                                # instances (installed or binary).
                                                                # If --usepkgonly is enabled, assume that
                                                                # the ebuild status should be ignored.
-                                                               if not use_ebuild_visibility and usepkgonly:
+                                                               if not use_ebuild_visibility and (usepkgonly or useoldpkg):
                                                                        if pkg.installed and pkg.masks:
                                                                                continue
                                                                else:
@@ -3419,7 +3446,7 @@ class depgraph(object):
                                                break
                                        # Compare built package to current config and
                                        # reject the built package if necessary.
-                                       if built and (not installed or matched_pkgs_ignore_use) and \
+                                       if built and not useoldpkg and (not installed or matched_pkgs_ignore_use) and \
                                                ("--newuse" in self._frozen_config.myopts or \
                                                "--reinstall" in self._frozen_config.myopts or \
                                                "--binpkg-respect-use" in self._frozen_config.myopts):
@@ -3434,7 +3461,7 @@ class depgraph(object):
                                                forced_flags.update(pkgsettings.useforce)
                                                forced_flags.update(pkgsettings.usemask)
                                                cur_iuse = iuses
-                                               if myeb and not usepkgonly:
+                                               if myeb and not usepkgonly and not useoldpkg:
                                                        cur_iuse = myeb.iuse.all
                                                if self._reinstall_for_flags(forced_flags,
                                                        old_use, iuses,
@@ -3442,7 +3469,7 @@ class depgraph(object):
                                                        break
                                        # Compare current config to installed package
                                        # and do not reinstall if possible.
-                                       if not installed and \
+                                       if not installed and not useoldpkg and \
                                                ("--newuse" in self._frozen_config.myopts or \
                                                "--reinstall" in self._frozen_config.myopts) and \
                                                cpv in vardb.match(atom):
@@ -3460,8 +3487,13 @@ class depgraph(object):
                                                        cur_use, cur_iuse)
                                                if reinstall_for_flags:
                                                        reinstall = True
+                                       if reinstall_atoms.findAtomForPackage(pkg, \
+                                                       modified_use=self._pkg_use_enabled(pkg)):
+                                               reinstall = True
                                        if not built:
                                                myeb = pkg
+                                       elif useoldpkg:
+                                               matched_oldpkg.append(pkg)
                                        matched_packages.append(pkg)
                                        if reinstall_for_flags:
                                                self._dynamic_config._reinstall_nodes[pkg] = \
@@ -3545,14 +3577,20 @@ class depgraph(object):
                                                allow_license_changes=allow_license_changes):
                                                return pkg, existing_node
 
-                       bestmatch = portage.best(
-                               [pkg.cpv for pkg in matched_packages \
+                       visible_matches = []
+                       if matched_oldpkg:
+                               visible_matches = [pkg.cpv for pkg in matched_oldpkg \
                                        if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords,
-                                               allow_license_changes=allow_license_changes)])
-                       if not bestmatch:
+                                               allow_license_changes=allow_license_changes)]
+                       if not visible_matches:
+                               visible_matches = [pkg.cpv for pkg in matched_packages \
+                                       if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords,
+                                               allow_license_changes=allow_license_changes)]
+                       if visible_matches:
+                               bestmatch = portage.best(visible_matches)
+                       else:
                                # all are masked, so ignore visibility
-                               bestmatch = portage.best(
-                                       [pkg.cpv for pkg in matched_packages])
+                               bestmatch = portage.best([pkg.cpv for pkg in matched_packages])
                        matched_packages = [pkg for pkg in matched_packages \
                                if portage.dep.cpvequal(pkg.cpv, bestmatch)]
 
index 96fee89ab484636a5f3b16b8f2a1aae355c64a20..6ae267f5a524fee3e45ddedbc19dd73955dddeb0 100644 (file)
@@ -544,6 +544,23 @@ def insert_optional_args(args):
 
        return new_args
 
+def _find_bad_atoms(atoms):
+       bad_atoms = []
+       for x in ' '.join(atoms).split():
+               bad_atom = False
+               try:
+                       atom = portage.dep.Atom(x, allow_wildcard=True)
+               except portage.exception.InvalidAtom:
+                       try:
+                               atom = portage.dep.Atom("*/"+x, allow_wildcard=True)
+                       except portage.exception.InvalidAtom:
+                               bad_atom = True
+
+               if bad_atom or atom.operator or atom.blocker or atom.use:
+                       bad_atoms.append(x)
+       return bad_atoms
+
+
 def parse_opts(tmpcmdline, silent=False):
        myaction=None
        myopts = {}
@@ -680,6 +697,14 @@ def parse_opts(tmpcmdline, silent=False):
                        "choices":["changed-use"]
                },
 
+               "--reinstall-atoms": {
+                       "help"   :"A space separated list of package names or slot atoms. " + \
+                               "Emerge will treat matching packages as if they are not " + \
+                               "installed, and reinstall them if necessary. Implies --deep.",
+
+                       "action" : "append",
+               },
+
                "--binpkg-respect-use": {
                        "help"    : "discard binary packages if their use flags \
                                don't match the current configuration",
@@ -701,6 +726,13 @@ def parse_opts(tmpcmdline, silent=False):
                        "choices"  : true_y_or_n
                },
 
+               "--nousepkg-atoms": {
+                       "help"   :"A space separated list of package names or slot atoms. " + \
+                               "Emerge will ignore matching binary packages. ",
+
+                       "action" : "append",
+               },
+
                "--package-moves": {
                        "help"     : "perform package moves when necessary",
                        "type"     : "choice",
@@ -764,6 +796,13 @@ def parse_opts(tmpcmdline, silent=False):
                        "choices"  : true_y_or_n
                },
 
+               "--useoldpkg-atoms": {
+                       "help"   :"A space separated list of package names or slot atoms. " + \
+                               "Emerge will prefer matching binary packages over newer unbuilt packages. ",
+
+                       "action" : "append",
+               },
+
                "--usepkg": {
                        "shortopt" : "-k",
                        "help"     : "use binary packages",
@@ -852,30 +891,29 @@ def parse_opts(tmpcmdline, silent=False):
                        myoptions.depclean_lib_check = True
 
        if myoptions.exclude:
-               exclude = []
-               bad_atoms = []
-               for x in ' '.join(myoptions.exclude).split():
-                       bad_atom = False
-                       try:
-                               atom = portage.dep.Atom(x, allow_wildcard=True)
-                       except portage.exception.InvalidAtom:
-                               try:
-                                       atom = portage.dep.Atom("*/"+x, allow_wildcard=True)
-                               except portage.exception.InvalidAtom:
-                                       bad_atom = True
-                       
-                       if bad_atom:
-                               bad_atoms.append(x)
-                       else:
-                               if atom.operator or atom.blocker or atom.use:
-                                       bad_atoms.append(x)
-                               else:
-                                       exclude.append(atom)
-
+               bad_atoms = _find_bad_atoms(myoptions.exclude)
                if bad_atoms and not silent:
                        parser.error("Invalid Atom(s) in --exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
                                (",".join(bad_atoms),))
 
+       if myoptions.reinstall_atoms:
+               bad_atoms = _find_bad_atoms(myoptions.reinstall_atoms)
+               if bad_atoms and not silent:
+                       parser.error("Invalid Atom(s) in --reinstall-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+                               (",".join(bad_atoms),))
+
+       if myoptions.nousepkg_atoms:
+               bad_atoms = _find_bad_atoms(myoptions.nousepkg_atoms)
+               if bad_atoms and not silent:
+                       parser.error("Invalid Atom(s) in --nousepkg-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+                               (",".join(bad_atoms),))
+
+       if myoptions.useoldpkg_atoms:
+               bad_atoms = _find_bad_atoms(myoptions.useoldpkg_atoms)
+               if bad_atoms and not silent:
+                       parser.error("Invalid Atom(s) in --useoldpkg-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \
+                               (",".join(bad_atoms),))
+
        if myoptions.fail_clean in true_y:
                myoptions.fail_clean = True