From: Fabian Groffen Date: Wed, 15 Apr 2009 16:59:19 +0000 (-0000) Subject: Merged from trunk -r13339:13345 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=7752bbff99608dec10d9d4fa19ada14fdbc64084;p=portage.git Merged from trunk -r13339:13345 | 13340 | Create the myreporoot variable from portdir_overlay before | | zmedico | doing realpath(portdir_overlay) since otherwise symlinks | | | break the assumptions. Thanks to Thomas Sachau | | | 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 --- diff --git a/bin/ebuild-helpers/prepall b/bin/ebuild-helpers/prepall index dfaacfd3c..84e41f213 100755 --- a/bin/ebuild-helpers/prepall +++ b/bin/ebuild-helpers/prepall @@ -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 diff --git a/bin/ebuild.sh b/bin/ebuild.sh index c7026a410..3ac2a7694 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -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 diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index c7508fbb2..6670bc4cd 100644 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -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 } diff --git a/bin/repoman b/bin/repoman index 78cd058c8..a0f8c62a0 100755 --- a/bin/repoman +++ b/bin/repoman @@ -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) diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 8c33769ca..fe2209064 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -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) diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index da1e5c2b7..2c0c6b55d 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -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"]: