Merged from trunk -r13339:13345
authorFabian Groffen <grobian@gentoo.org>
Wed, 15 Apr 2009 16:59:19 +0000 (16:59 -0000)
committerFabian Groffen <grobian@gentoo.org>
Wed, 15 Apr 2009 16:59:19 +0000 (16:59 -0000)
   | 13340   | Create the myreporoot variable from portdir_overlay before   |
   | zmedico | doing realpath(portdir_overlay) since otherwise symlinks     |
   |         | break the assumptions. Thanks to Thomas Sachau <tommy@g.o>   |
   |         | for reporting and troubleshooting.                           |

   | 13342   | Make portage.bsd_chflags correspond to FEATURES=chflags so   |
   | zmedico | that it can be used for related conditionals in shell code.  |

   | 13343   | Convert portage.bsd_chflags into a class with chflags() and  |
   | zmedico | lchflags() class methods.                                    |

   | 13344   | Split out an action_uninstall() function to handle argument  |
   | zmedico | validation for clean, depclean, prune, and unmerge actions.  |

   | 13345   | Add support in action_uninstall() for file -> package        |
   | zmedico | lookup.                                                      |

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

bin/ebuild-helpers/prepall
bin/ebuild.sh
bin/misc-functions.sh
bin/repoman
pym/_emerge/__init__.py
pym/portage/__init__.py

index dfaacfd3c9786ddf5c010215bd7777169b35197d..84e41f2139de77ea99823bc5a7d33caedb6805ee 100755 (executable)
@@ -5,7 +5,7 @@
 
 source "${PORTAGE_BIN_PATH:-@PORTAGE_BASE@/bin}"/isolated-functions.sh
 
-if type -P chflags > /dev/null && type -P mtree > /dev/null ; then
+if hasq chflags $FEATURES ; then
        # Save all the file flags for restoration at the end of prepall.
        mtree -c -p "${ED}" -k flags > "${T}/bsdflags.mtree"
        # Remove all the file flags so that prepall can do anything necessary.
@@ -18,7 +18,7 @@ prepallinfo
 
 prepallstrip
 
-if type -P chflags > /dev/null && type -P mtree > /dev/null; then
+if hasq chflags $FEATURES ; then
        # Restore all the file flags that were saved at the beginning of prepall.
        mtree -U -e -p "${ED}" -k flags < "${T}/bsdflags.mtree" &> /dev/null
 fi
index c7026a41074078d4b7520fad3b0fcfdc5c36126f..3ac2a76942efdda5480f6dcb069d83b06dd9417a 100755 (executable)
@@ -707,7 +707,7 @@ dyn_clean() {
        elif [ ! -d "${PORTAGE_BUILDDIR}" ] ; then
                return 0
        fi
-       if type -P chflags > /dev/null ; then
+       if hasq chflags $FEATURES ; then
                chflags -R noschg,nouchg,nosappnd,nouappnd "${PORTAGE_BUILDDIR}"
                chflags -R nosunlnk,nouunlnk "${PORTAGE_BUILDDIR}" 2>/dev/null
        fi
index c7508fbb2655f95a22894c2942275f041c9cce19..6670bc4cd333ae95083b266180223874beb48c32 100644 (file)
@@ -613,8 +613,7 @@ install_mask() {
 }
 
 preinst_bsdflags() {
-       type -P chflags > /dev/null || return 0
-       type -P mtree > /dev/null || return 1
+       hasq chflags $FEATURES || return
        # Save all the file flags for restoration after installation.
        mtree -c -p "${ED}" -k flags > "${T}/bsdflags.mtree"
        # Remove all the file flags so that the merge phase can do anything
@@ -624,8 +623,7 @@ preinst_bsdflags() {
 }
 
 postinst_bsdflags() {
-       type -P chflags > /dev/null || return 0
-       type -P mtree > /dev/null || return 1
+       hasq chflags $FEATURES || return
        # Restore all the file flags that were saved before installation.
        mtree -e -p "${EROOT}" -U -k flags < "${T}/bsdflags.mtree" &> /dev/null
 }
index 78cd058c89b484ec70cb05bc8e134c61cdb17820..a0f8c62a03a0b6a8458b1c65aa254250c8958a88 100755 (executable)
@@ -440,6 +440,9 @@ portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
 if portdir is None:
        sys.exit(1)
 
+myreporoot = os.path.basename(portdir_overlay)
+myreporoot += mydir[len(portdir_overlay):]
+
 vcs = None
 if os.path.isdir("CVS"):
        vcs = "cvs"
@@ -515,9 +518,6 @@ root_config = RootConfig(repoman_settings, trees[root], None)
 portdb._aux_cache_keys.clear()
 portdb._aux_cache_keys.update(["EAPI", "KEYWORDS", "SLOT"])
 
-myreporoot = os.path.basename(portdir_overlay)
-myreporoot += mydir[len(portdir_overlay):]
-
 reposplit = myreporoot.split(os.path.sep)
 repolevel = len(reposplit)
 
index 8c33769ca7eb366662f8e4a6b33a316115366176..fe2209064512828e15a89d9c95d54acb59ee9c8e 100644 (file)
@@ -13862,6 +13862,105 @@ def action_search(root_config, myopts, myfiles, spinner):
                                sys.exit(1)
                        searchinstance.output()
 
+def action_uninstall(settings, trees, ldpath_mtimes,
+       opts, action, files, spinner):
+
+       # For backward compat, some actions do not require leading '='.
+       ignore_missing_eq = action in ('clean', 'unmerge')
+       root = settings['ROOT']
+       vardb = trees[root]['vartree'].dbapi
+       valid_atoms = []
+       lookup_owners = []
+
+       # Ensure atoms are valid before calling unmerge().
+       # For backward compat, leading '=' is not required.
+       for x in files:
+               if is_valid_package_atom(x) or \
+                       (ignore_missing_eq and is_valid_package_atom('=' + x)):
+
+                       try:
+                               valid_atoms.append(
+                                       portage.dep_expand(x, mydb=vardb, settings=settings))
+                       except portage.exception.AmbiguousPackageName, e:
+                               msg = "The short ebuild name \"" + x + \
+                                       "\" is ambiguous.  Please specify " + \
+                                       "one of the following " + \
+                                       "fully-qualified ebuild names instead:"
+                               for line in textwrap.wrap(msg, 70):
+                                       writemsg_level("!!! %s\n" % (line,),
+                                               level=logging.ERROR, noiselevel=-1)
+                               for i in e[0]:
+                                       writemsg_level("    %s\n" % colorize("INFORM", i),
+                                               level=logging.ERROR, noiselevel=-1)
+                               writemsg_level("\n", level=logging.ERROR, noiselevel=-1)
+                               return 1
+
+               elif x.startswith(os.sep):
+                       if not x.startswith(root):
+                               writemsg_level(("!!! '%s' does not start with" + \
+                                       " $ROOT.\n") % x, level=logging.ERROR, noiselevel=-1)
+                               return 1
+                       # Queue these up since it's most efficient to handle
+                       # multiple files in a single iter_owners() call.
+                       lookup_owners.append(x)
+
+               else:
+                       msg = []
+                       msg.append("'%s' is not a valid package atom." % (x,))
+                       msg.append("Please check ebuild(5) for full details.")
+                       writemsg_level("".join("!!! %s\n" % line for line in msg),
+                               level=logging.ERROR, noiselevel=-1)
+                       return 1
+
+       if lookup_owners:
+               relative_paths = []
+               search_for_multiple = False
+               if len(lookup_owners) > 1:
+                       search_for_multiple = True
+
+               for x in lookup_owners:
+                       if not search_for_multiple and os.path.isdir(x):
+                               search_for_multiple = True
+                       relative_paths.append(x[len(root):])
+
+               owners = set()
+               for pkg, relative_path in \
+                       vardb._owners.iter_owners(relative_paths):
+                       owners.add(pkg.mycpv)
+                       if not search_for_multiple:
+                               break
+
+               if owners:
+                       for cpv in owners:
+                               slot = vardb.aux_get(cpv, ['SLOT'])[0]
+                               if not slot:
+                                       # portage now masks packages with missing slot, but it's
+                                       # possible that one was installed by an older version
+                                       atom = portage.cpv_getkey(cpv)
+                               else:
+                                       atom = '%s:%s' % (portage.cpv_getkey(cpv), slot)
+                               valid_atoms.append(portage.dep.Atom(atom))
+               else:
+                       writemsg_level(("!!! '%s' is not claimed " + \
+                               "by any package.\n") % lookup_owners[0],
+                               level=logging.WARNING, noiselevel=-1)
+
+       if files and not valid_atoms:
+               return 1
+
+       if action in ('clean', 'unmerge') or \
+               (action == 'prune' and "--nodeps" in opts):
+               # When given a list of atoms, unmerge them in the order given.
+               ordered = action == 'unmerge'
+               unmerge(trees[settings["ROOT"]]['root_config'], opts, action,
+                       valid_atoms, ldpath_mtimes, ordered=ordered)
+               rval = os.EX_OK
+       else:
+               rval = action_depclean(settings, trees, ldpath_mtimes,
+                       opts, action, valid_atoms, spinner)
+
+       return rval
+
 def action_depclean(settings, trees, ldpath_mtimes,
        myopts, action, myfiles, spinner):
        # Kill packages that aren't explicitly merged or are required as a
@@ -13938,28 +14037,7 @@ def action_depclean(settings, trees, ldpath_mtimes,
        import textwrap
        args_set = InternalPackageSet()
        if myfiles:
-               for x in myfiles:
-                       if not is_valid_package_atom(x):
-                               writemsg_level("!!! '%s' is not a valid package atom.\n" % x,
-                                       level=logging.ERROR, noiselevel=-1)
-                               writemsg_level("!!! Please check ebuild(5) for full details.\n")
-                               return
-                       try:
-                               atom = portage.dep_expand(x, mydb=vardb, settings=settings)
-                       except portage.exception.AmbiguousPackageName, e:
-                               msg = "The short ebuild name \"" + x + \
-                                       "\" is ambiguous.  Please specify " + \
-                                       "one of the following " + \
-                                       "fully-qualified ebuild names instead:"
-                               for line in textwrap.wrap(msg, 70):
-                                       writemsg_level("!!! %s\n" % (line,),
-                                               level=logging.ERROR, noiselevel=-1)
-                               for i in e[0]:
-                                       writemsg_level("    %s\n" % colorize("INFORM", i),
-                                               level=logging.ERROR, noiselevel=-1)
-                               writemsg_level("\n", level=logging.ERROR, noiselevel=-1)
-                               return
-                       args_set.add(atom)
+               args_set.update(myfiles)
                matched_packages = False
                for x in args_set:
                        if vardb.match(x):
@@ -15935,32 +16013,16 @@ def emerge_main():
                validate_ebuild_environment(trees)
                action_search(trees[settings["ROOT"]]["root_config"],
                        myopts, myfiles, spinner)
-       elif myaction in ("clean", "unmerge") or \
-               (myaction == "prune" and "--nodeps" in myopts):
-               validate_ebuild_environment(trees)
-
-               # Ensure atoms are valid before calling unmerge().
-               # For backward compat, leading '=' is not required.
-               for x in myfiles:
-                       if is_valid_package_atom(x) or \
-                               is_valid_package_atom("=" + x):
-                               continue
-                       msg = []
-                       msg.append("'%s' is not a valid package atom." % (x,))
-                       msg.append("Please check ebuild(5) for full details.")
-                       writemsg_level("".join("!!! %s\n" % line for line in msg),
-                               level=logging.ERROR, noiselevel=-1)
-                       return 1
 
-               # When given a list of atoms, unmerge
-               # them in the order given.
-               ordered = myaction == "unmerge"
-               if 1 == unmerge(root_config, myopts, myaction, myfiles,
-                       mtimedb["ldpath"], ordered=ordered):
-                       if not (buildpkgonly or fetchonly or pretend):
-                               post_emerge(root_config, myopts, mtimedb, os.EX_OK)
+       elif myaction in ('clean', 'depclean', 'prune', 'unmerge'):
+               validate_ebuild_environment(trees)
+               rval = action_uninstall(settings, trees, mtimedb["ldpath"],
+                       myopts, myaction, myfiles, spinner)
+               if not (buildpkgonly or fetchonly or pretend):
+                       post_emerge(root_config, myopts, mtimedb, rval)
+               return rval
 
-       elif myaction in ("depclean", "info", "prune"):
+       elif myaction == 'info':
 
                # Ensure atoms are valid before calling unmerge().
                vardb = trees[settings["ROOT"]]["vartree"].dbapi
@@ -15991,14 +16053,8 @@ def emerge_main():
                                level=logging.ERROR, noiselevel=-1)
                        return 1
 
-               if myaction == "info":
-                       return action_info(settings, trees, myopts, valid_atoms)
+               return action_info(settings, trees, myopts, valid_atoms)
 
-               validate_ebuild_environment(trees)
-               action_depclean(settings, trees, mtimedb["ldpath"],
-                       myopts, myaction, valid_atoms, spinner)
-               if not (buildpkgonly or fetchonly or pretend):
-                       post_emerge(root_config, myopts, mtimedb, os.EX_OK)
        # "update", "system", or just process files:
        else:
                validate_ebuild_environment(trees)
index da1e5c2b75842a900517cd9c7413787434131ba2..2c0c6b55dbd004a81ec1e33585d9d17ce891024e 100644 (file)
@@ -43,35 +43,6 @@ except ImportError, e:
        sys.stderr.write("    "+str(e)+"\n\n");
        raise
 
-bsd_chflags = None
-if platform.system() in ["FreeBSD"]:
-       def bsd_chflags():
-               pass
-       def _chflags(path, flags, opts=""):
-               cmd = "chflags %s %o '%s'" % (opts, flags, path)
-               status, output = commands.getstatusoutput(cmd)
-               if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
-                       return
-               # Try to generate an ENOENT error if appropriate.
-               if "h" in opts:
-                       os.lstat(path)
-               else:
-                       os.stat(path)
-               # Make sure the binary exists.
-               if not portage.process.find_binary("chflags"):
-                       raise portage.exception.CommandNotFound("chflags")
-               # Now we're not sure exactly why it failed or what
-               # the real errno was, so just report EPERM.
-               e = OSError(errno.EPERM, output)
-               e.errno = errno.EPERM
-               e.filename = path
-               e.message = output
-               raise e
-       def _lchflags(path, flags):
-               return _chflags(path, flags, opts="-h")
-       bsd_chflags.chflags = _chflags
-       bsd_chflags.lchflags = _lchflags
-
 try:
        from portage.cache.cache_errors import CacheError
        import portage.proxy.lazyimport
@@ -150,6 +121,48 @@ except ImportError:
 # END OF IMPORTS -- END OF IMPORTS -- END OF IMPORTS -- END OF IMPORTS -- END
 # ===========================================================================
 
+def _shell_quote(s):
+       """
+       Quote a string in double-quotes and use backslashes to
+       escape any backslashes, double-quotes, dollar signs, or
+       backquotes in the string.
+       """
+       for letter in "\\\"$`":
+               if letter in s:
+                       s = s.replace(letter, "\\" + letter)
+       return "\"%s\"" % s
+
+bsd_chflags = None
+
+if platform.system() in ('FreeBSD',):
+
+       class bsd_chflags(object):
+
+               @classmethod
+               def chflags(cls, path, flags, opts=""):
+                       cmd = 'chflags %s %o %s' % (opts, flags, _shell_quote(path))
+                       status, output = commands.getstatusoutput(cmd)
+                       if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
+                               return
+                       # Try to generate an ENOENT error if appropriate.
+                       if 'h' in opts:
+                               os.lstat(path)
+                       else:
+                               os.stat(path)
+                       # Make sure the binary exists.
+                       if not portage.process.find_binary('chflags'):
+                               raise portage.exception.CommandNotFound('chflags')
+                       # Now we're not sure exactly why it failed or what
+                       # the real errno was, so just report EPERM.
+                       e = OSError(errno.EPERM, output)
+                       e.errno = errno.EPERM
+                       e.filename = path
+                       e.message = output
+                       raise e
+
+               @classmethod
+               def lchflags(cls, path, flags):
+                       return cls.chflags(path, flags, opts='-h')
 
 def load_mod(name):
        modname = ".".join(name.split(".")[:-1])
@@ -1853,6 +1866,9 @@ class config(object):
                                if "usersandbox" in self.features:
                                        self.features.remove("usersandbox")
 
+                       if bsd_chflags:
+                               self.features.add('chflags')
+
                        self["FEATURES"] = " ".join(sorted(self.features))
                        self.backup_changes("FEATURES")
                        global _glep_55_enabled, _validate_cache_for_unsupported_eapis
@@ -3169,17 +3185,6 @@ class config(object):
                keys = __iter__
                items = iteritems
 
-def _shell_quote(s):
-       """
-       Quote a string in double-quotes and use backslashes to
-       escape any backslashes, double-quotes, dollar signs, or
-       backquotes in the string.
-       """
-       for letter in "\\\"$`":
-               if letter in s:
-                       s = s.replace(letter, "\\" + letter)
-       return "\"%s\"" % s
-
 # In some cases, openpty can be slow when it fails. Therefore,
 # stop trying to use it after the first failure.
 if platform.system() in ["SunOS"]: