From 65e69242814553b826b9277495a5f62b79569269 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Tue, 16 Oct 2012 01:33:54 -0700 Subject: emerge_main: split out run_action Also move post_emerge and chk_updated_cfg_files to separate files. --- pym/_emerge/actions.py | 777 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 738 insertions(+), 39 deletions(-) (limited to 'pym/_emerge/actions.py') diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py index 3003afc65..3336e9fca 100644 --- a/pym/_emerge/actions.py +++ b/pym/_emerge/actions.py @@ -22,13 +22,18 @@ from itertools import chain import portage portage.proxy.lazyimport.lazyimport(globals(), + 'portage.debug', 'portage.news:count_unread_news,display_news_notifications', + '_emerge.chk_updated_cfg_files:chk_updated_cfg_files', + '_emerge.help:help@emerge_help', + '_emerge.post_emerge:display_news_notification,post_emerge', + '_emerge.stdout_spinner:stdout_spinner', ) from portage.localization import _ from portage import os from portage import shutil -from portage import eapi_is_supported, _unicode_decode +from portage import eapi_is_supported, _encodings, _unicode_decode from portage.cache.cache_errors import CacheError from portage.const import GLOBAL_CONFIG_PATH from portage.const import _DEPCLEAN_LIB_CHECK_DEFAULT @@ -38,7 +43,7 @@ from portage.dep import Atom from portage.eclass_cache import hashed_path from portage.exception import InvalidAtom, InvalidData from portage.output import blue, bold, colorize, create_color_func, darkgreen, \ - red, yellow + red, xtermTitle, xtermTitleReset, yellow good = create_color_func("GOOD") bad = create_color_func("BAD") warn = create_color_func("WARN") @@ -46,7 +51,7 @@ from portage.package.ebuild._ipc.QueryCommand import QueryCommand from portage.package.ebuild.doebuild import _check_temp_dir from portage._sets import load_default_config, SETPREFIX from portage._sets.base import InternalPackageSet -from portage.util import cmp_sort_key, writemsg, \ +from portage.util import cmp_sort_key, writemsg, varexpand, \ writemsg_level, writemsg_stdout from portage.util.digraph import digraph from portage.util._async.SchedulerInterface import SchedulerInterface @@ -82,6 +87,21 @@ if sys.hexversion >= 0x3000000: else: _unicode = unicode +COWSAY_MOO = """ + + Larry loves Gentoo (%s) + + _______________________ +< Have you mooed today? > + ----------------------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || + +""" + def action_build(settings, trees, mtimedb, myopts, myaction, myfiles, spinner): @@ -3057,42 +3077,6 @@ def load_emerge_config(trees=None): QueryCommand._db = trees return settings, trees, mtimedb -def chk_updated_cfg_files(eroot, config_protect): - target_root = eroot - result = list( - portage.util.find_updated_config_files(target_root, config_protect)) - - for x in result: - writemsg_level("\n %s " % (colorize("WARN", "* " + _("IMPORTANT:"))), - level=logging.INFO, noiselevel=-1) - if not x[1]: # it's a protected file - writemsg_level( _("config file '%s' needs updating.\n") % x[0], - level=logging.INFO, noiselevel=-1) - else: # it's a protected dir - if len(x[1]) == 1: - head, tail = os.path.split(x[1][0]) - tail = tail[len("._cfg0000_"):] - fpath = os.path.join(head, tail) - writemsg_level(_("config file '%s' needs updating.\n") % fpath, - level=logging.INFO, noiselevel=-1) - else: - writemsg_level( _("%d config files in '%s' need updating.\n") % \ - (len(x[1]), x[0]), level=logging.INFO, noiselevel=-1) - - if result: - print(" "+yellow("*")+ " See the "+colorize("INFORM", _("CONFIGURATION FILES"))\ - + " " + _("section of the") + " " + bold("emerge")) - print(" "+yellow("*")+ " " + _("man page to learn how to update config files.")) - - -def display_news_notification(root_config, myopts): - if "news" not in root_config.settings.features: - return - portdb = root_config.trees["porttree"].dbapi - vardb = root_config.trees["vartree"].dbapi - news_counts = count_unread_news(portdb, vardb) - display_news_notifications(news_counts) - def getgccversion(chost): """ rtype: C{str} @@ -3147,3 +3131,718 @@ def getgccversion(chost): portage.writemsg(gcc_not_found_error, noiselevel=-1) return "[unavailable]" + +# Warn about features that may confuse users and +# lead them to report invalid bugs. +_emerge_features_warn = frozenset(['keeptemp', 'keepwork']) + +def validate_ebuild_environment(trees): + features_warn = set() + for myroot in trees: + settings = trees[myroot]["vartree"].settings + settings.validate() + features_warn.update( + _emerge_features_warn.intersection(settings.features)) + + if features_warn: + msg = "WARNING: The FEATURES variable contains one " + \ + "or more values that should be disabled under " + \ + "normal circumstances: %s" % " ".join(features_warn) + out = portage.output.EOutput() + for line in textwrap.wrap(msg, 65): + out.ewarn(line) + +def check_procfs(): + procfs_path = '/proc' + if platform.system() not in ("Linux",) or \ + os.path.ismount(procfs_path): + return os.EX_OK + msg = "It seems that %s is not mounted. You have been warned." % procfs_path + writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)), + level=logging.ERROR, noiselevel=-1) + return 1 + +def config_protect_check(trees): + for root, root_trees in trees.items(): + settings = root_trees["root_config"].settings + if not settings.get("CONFIG_PROTECT"): + msg = "!!! CONFIG_PROTECT is empty" + if settings["ROOT"] != "/": + msg += " for '%s'" % root + msg += "\n" + writemsg_level(msg, level=logging.WARN, noiselevel=-1) + +def apply_priorities(settings): + ionice(settings) + nice(settings) + +def nice(settings): + try: + os.nice(int(settings.get("PORTAGE_NICENESS", "0"))) + except (OSError, ValueError) as e: + out = portage.output.EOutput() + out.eerror("Failed to change nice value to '%s'" % \ + settings["PORTAGE_NICENESS"]) + out.eerror("%s\n" % str(e)) + +def ionice(settings): + + ionice_cmd = settings.get("PORTAGE_IONICE_COMMAND") + if ionice_cmd: + ionice_cmd = portage.util.shlex_split(ionice_cmd) + if not ionice_cmd: + return + + variables = {"PID" : str(os.getpid())} + cmd = [varexpand(x, mydict=variables) for x in ionice_cmd] + + try: + rval = portage.process.spawn(cmd, env=os.environ) + except portage.exception.CommandNotFound: + # The OS kernel probably doesn't support ionice, + # so return silently. + return + + if rval != os.EX_OK: + out = portage.output.EOutput() + out.eerror("PORTAGE_IONICE_COMMAND returned %d" % (rval,)) + out.eerror("See the make.conf(5) man page for PORTAGE_IONICE_COMMAND usage instructions.") + +def setconfig_fallback(root_config): + setconfig = root_config.setconfig + setconfig._create_default_config() + setconfig._parse(update=True) + root_config.sets = setconfig.getSets() + +def get_missing_sets(root_config): + # emerge requires existence of "world", "selected", and "system" + missing_sets = [] + + for s in ("selected", "system", "world",): + if s not in root_config.sets: + missing_sets.append(s) + + return missing_sets + +def missing_sets_warning(root_config, missing_sets): + if len(missing_sets) > 2: + missing_sets_str = ", ".join('"%s"' % s for s in missing_sets[:-1]) + missing_sets_str += ', and "%s"' % missing_sets[-1] + elif len(missing_sets) == 2: + missing_sets_str = '"%s" and "%s"' % tuple(missing_sets) + else: + missing_sets_str = '"%s"' % missing_sets[-1] + msg = ["emerge: incomplete set configuration, " + \ + "missing set(s): %s" % missing_sets_str] + if root_config.sets: + msg.append(" sets defined: %s" % ", ".join(root_config.sets)) + global_config_path = portage.const.GLOBAL_CONFIG_PATH + if root_config.settings['EPREFIX']: + global_config_path = os.path.join(root_config.settings['EPREFIX'], + portage.const.GLOBAL_CONFIG_PATH.lstrip(os.sep)) + msg.append(" This usually means that '%s'" % \ + (os.path.join(global_config_path, "sets/portage.conf"),)) + msg.append(" is missing or corrupt.") + msg.append(" Falling back to default world and system set configuration!!!") + for line in msg: + writemsg_level(line + "\n", level=logging.ERROR, noiselevel=-1) + +def ensure_required_sets(trees): + warning_shown = False + for root_trees in trees.values(): + missing_sets = get_missing_sets(root_trees["root_config"]) + if missing_sets and not warning_shown: + warning_shown = True + missing_sets_warning(root_trees["root_config"], missing_sets) + if missing_sets: + setconfig_fallback(root_trees["root_config"]) + +def expand_set_arguments(myfiles, myaction, root_config): + retval = os.EX_OK + setconfig = root_config.setconfig + + sets = setconfig.getSets() + + # In order to know exactly which atoms/sets should be added to the + # world file, the depgraph performs set expansion later. It will get + # confused about where the atoms came from if it's not allowed to + # expand them itself. + do_not_expand = (None, ) + newargs = [] + for a in myfiles: + if a in ("system", "world"): + newargs.append(SETPREFIX+a) + else: + newargs.append(a) + myfiles = newargs + del newargs + newargs = [] + + # separators for set arguments + ARG_START = "{" + ARG_END = "}" + + for i in range(0, len(myfiles)): + if myfiles[i].startswith(SETPREFIX): + start = 0 + end = 0 + x = myfiles[i][len(SETPREFIX):] + newset = "" + while x: + start = x.find(ARG_START) + end = x.find(ARG_END) + if start > 0 and start < end: + namepart = x[:start] + argpart = x[start+1:end] + + # TODO: implement proper quoting + args = argpart.split(",") + options = {} + for a in args: + if "=" in a: + k, v = a.split("=", 1) + options[k] = v + else: + options[a] = "True" + setconfig.update(namepart, options) + newset += (x[:start-len(namepart)]+namepart) + x = x[end+len(ARG_END):] + else: + newset += x + x = "" + myfiles[i] = SETPREFIX+newset + + sets = setconfig.getSets() + + # display errors that occurred while loading the SetConfig instance + for e in setconfig.errors: + print(colorize("BAD", "Error during set creation: %s" % e)) + + unmerge_actions = ("unmerge", "prune", "clean", "depclean") + + for a in myfiles: + if a.startswith(SETPREFIX): + s = a[len(SETPREFIX):] + if s not in sets: + display_missing_pkg_set(root_config, s) + return (None, 1) + if s == "installed": + msg = ("The @installed set is deprecated and will soon be " + "removed. Please refer to bug #387059 for details.") + out = portage.output.EOutput() + for line in textwrap.wrap(msg, 50): + out.ewarn(line) + setconfig.active.append(s) + try: + set_atoms = setconfig.getSetAtoms(s) + except portage.exception.PackageSetNotFound as e: + writemsg_level(("emerge: the given set '%s' " + \ + "contains a non-existent set named '%s'.\n") % \ + (s, e), level=logging.ERROR, noiselevel=-1) + if s in ('world', 'selected') and \ + SETPREFIX + e.value in sets['selected']: + writemsg_level(("Use `emerge --deselect %s%s` to " + "remove this set from world_sets.\n") % + (SETPREFIX, e,), level=logging.ERROR, + noiselevel=-1) + return (None, 1) + if myaction in unmerge_actions and \ + not sets[s].supportsOperation("unmerge"): + sys.stderr.write("emerge: the given set '%s' does " % s + \ + "not support unmerge operations\n") + retval = 1 + elif not set_atoms: + print("emerge: '%s' is an empty set" % s) + elif myaction not in do_not_expand: + newargs.extend(set_atoms) + else: + newargs.append(SETPREFIX+s) + for e in sets[s].errors: + print(e) + else: + newargs.append(a) + return (newargs, retval) + +def repo_name_check(trees): + missing_repo_names = set() + for root_trees in trees.values(): + porttree = root_trees.get("porttree") + if porttree: + portdb = porttree.dbapi + missing_repo_names.update(portdb.getMissingRepoNames()) + if portdb.porttree_root in missing_repo_names and \ + not os.path.exists(os.path.join( + portdb.porttree_root, "profiles")): + # This is normal if $PORTDIR happens to be empty, + # so don't warn about it. + missing_repo_names.remove(portdb.porttree_root) + + if missing_repo_names: + msg = [] + msg.append("WARNING: One or more repositories " + \ + "have missing repo_name entries:") + msg.append("") + for p in missing_repo_names: + msg.append("\t%s/profiles/repo_name" % (p,)) + msg.append("") + msg.extend(textwrap.wrap("NOTE: Each repo_name entry " + \ + "should be a plain text file containing a unique " + \ + "name for the repository on the first line.", 70)) + msg.append("\n") + writemsg_level("".join("%s\n" % l for l in msg), + level=logging.WARNING, noiselevel=-1) + + return bool(missing_repo_names) + +def repo_name_duplicate_check(trees): + ignored_repos = {} + for root, root_trees in trees.items(): + if 'porttree' in root_trees: + portdb = root_trees['porttree'].dbapi + if portdb.settings.get('PORTAGE_REPO_DUPLICATE_WARN') != '0': + for repo_name, paths in portdb.getIgnoredRepos(): + k = (root, repo_name, portdb.getRepositoryPath(repo_name)) + ignored_repos.setdefault(k, []).extend(paths) + + if ignored_repos: + msg = [] + msg.append('WARNING: One or more repositories ' + \ + 'have been ignored due to duplicate') + msg.append(' profiles/repo_name entries:') + msg.append('') + for k in sorted(ignored_repos): + msg.append(' %s overrides' % ", ".join(k)) + for path in ignored_repos[k]: + msg.append(' %s' % (path,)) + msg.append('') + msg.extend(' ' + x for x in textwrap.wrap( + "All profiles/repo_name entries must be unique in order " + \ + "to avoid having duplicates ignored. " + \ + "Set PORTAGE_REPO_DUPLICATE_WARN=\"0\" in " + \ + "/etc/make.conf if you would like to disable this warning.")) + msg.append("\n") + writemsg_level(''.join('%s\n' % l for l in msg), + level=logging.WARNING, noiselevel=-1) + + return bool(ignored_repos) + +def run_action(settings, trees, mtimedb, myaction, myopts, myfiles): + + # skip global updates prior to sync, since it's called after sync + if myaction not in ('help', 'info', 'sync', 'version') and \ + myopts.get('--package-moves') != 'n' and \ + _global_updates(trees, mtimedb["updates"], quiet=("--quiet" in myopts)): + mtimedb.commit() + # Reload the whole config from scratch. + settings, trees, mtimedb = load_emerge_config(trees=trees) + + xterm_titles = "notitles" not in settings.features + if xterm_titles: + xtermTitle("emerge") + + if "--digest" in myopts: + os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest" + # Reload the whole config from scratch so that the portdbapi internal + # config is updated with new FEATURES. + settings, trees, mtimedb = load_emerge_config(trees=trees) + + # NOTE: adjust_configs() can map options to FEATURES, so any relevant + # options adjustments should be made prior to calling adjust_configs(). + if "--buildpkgonly" in myopts: + myopts["--buildpkg"] = True + + if "getbinpkg" in settings.features: + myopts["--getbinpkg"] = True + + if "--getbinpkgonly" in myopts: + myopts["--getbinpkg"] = True + + if "--getbinpkgonly" in myopts: + myopts["--usepkgonly"] = True + + if "--getbinpkg" in myopts: + myopts["--usepkg"] = True + + if "--usepkgonly" in myopts: + myopts["--usepkg"] = True + + if "--buildpkgonly" in myopts: + # --buildpkgonly will not merge anything, so + # it cancels all binary package options. + for opt in ("--getbinpkg", "--getbinpkgonly", + "--usepkg", "--usepkgonly"): + myopts.pop(opt, None) + + adjust_configs(myopts, trees) + apply_priorities(settings) + + if myaction == 'version': + writemsg_stdout(getportageversion( + settings["PORTDIR"], None, + settings.profile_path, settings["CHOST"], + trees[settings['EROOT']]['vartree'].dbapi) + '\n', noiselevel=-1) + return 0 + elif myaction == 'help': + emerge_help() + return 0 + + spinner = stdout_spinner() + if "candy" in settings.features: + spinner.update = spinner.update_scroll + + if "--quiet" not in myopts: + portage.deprecated_profile_check(settings=settings) + if portage.const._ENABLE_REPO_NAME_WARN: + # Bug #248603 - Disable warnings about missing + # repo_name entries for stable branch. + repo_name_check(trees) + repo_name_duplicate_check(trees) + config_protect_check(trees) + check_procfs() + + for mytrees in trees.values(): + mydb = mytrees["porttree"].dbapi + # Freeze the portdbapi for performance (memoize all xmatch results). + mydb.freeze() + + if myaction in ('search', None) and \ + "--usepkg" in myopts: + # Populate the bintree with current --getbinpkg setting. + # This needs to happen before expand_set_arguments(), in case + # any sets use the bintree. + mytrees["bintree"].populate( + getbinpkgs="--getbinpkg" in myopts) + + del mytrees, mydb + + if "moo" in myfiles: + print(COWSAY_MOO % platform.system()) + msg = ("The above `emerge moo` display is deprecated. " + "Please use `emerge --moo` instead.") + for line in textwrap.wrap(msg, 50): + print(" %s %s" % (colorize("WARN", "*"), line)) + + for x in myfiles: + ext = os.path.splitext(x)[1] + if (ext == ".ebuild" or ext == ".tbz2") and \ + os.path.exists(os.path.abspath(x)): + print(colorize("BAD", "\n*** emerging by path is broken " + "and may not always work!!!\n")) + break + + root_config = trees[settings['EROOT']]['root_config'] + if myaction == "moo": + print(COWSAY_MOO % platform.system()) + return os.EX_OK + elif myaction == "list-sets": + writemsg_stdout("".join("%s\n" % s for s in sorted(root_config.sets))) + return os.EX_OK + elif myaction == "check-news": + news_counts = count_unread_news( + root_config.trees["porttree"].dbapi, + root_config.trees["vartree"].dbapi) + if any(news_counts.values()): + display_news_notifications(news_counts) + elif "--quiet" not in myopts: + print("", colorize("GOOD", "*"), "No news items were found.") + return os.EX_OK + + ensure_required_sets(trees) + + # only expand sets for actions taking package arguments + oldargs = myfiles[:] + if myaction in ("clean", "config", "depclean", + "info", "prune", "unmerge", None): + myfiles, retval = expand_set_arguments(myfiles, myaction, root_config) + if retval != os.EX_OK: + return retval + + # Need to handle empty sets specially, otherwise emerge will react + # with the help message for empty argument lists + if oldargs and not myfiles: + print("emerge: no targets left after set expansion") + return 0 + + if ("--tree" in myopts) and ("--columns" in myopts): + print("emerge: can't specify both of \"--tree\" and \"--columns\".") + return 1 + + if '--emptytree' in myopts and '--noreplace' in myopts: + writemsg_level("emerge: can't specify both of " + \ + "\"--emptytree\" and \"--noreplace\".\n", + level=logging.ERROR, noiselevel=-1) + return 1 + + if ("--quiet" in myopts): + spinner.update = spinner.update_quiet + portage.util.noiselimit = -1 + + if "--fetch-all-uri" in myopts: + myopts["--fetchonly"] = True + + if "--skipfirst" in myopts and "--resume" not in myopts: + myopts["--resume"] = True + + # Allow -p to remove --ask + if "--pretend" in myopts: + myopts.pop("--ask", None) + + # forbid --ask when not in a terminal + # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. + if ("--ask" in myopts) and (not sys.stdin.isatty()): + portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n", + noiselevel=-1) + return 1 + + if settings.get("PORTAGE_DEBUG", "") == "1": + spinner.update = spinner.update_quiet + portage.util.noiselimit = 0 + if "python-trace" in settings.features: + portage.debug.set_trace(True) + + if not ("--quiet" in myopts): + if '--nospinner' in myopts or \ + settings.get('TERM') == 'dumb' or \ + not sys.stdout.isatty(): + spinner.update = spinner.update_basic + + if "--debug" in myopts: + print("myaction", myaction) + print("myopts", myopts) + + if not myaction and not myfiles and "--resume" not in myopts: + emerge_help() + return 1 + + pretend = "--pretend" in myopts + fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts + buildpkgonly = "--buildpkgonly" in myopts + + # check if root user is the current user for the actions where emerge needs this + if portage.data.secpass < 2: + # We've already allowed "--version" and "--help" above. + if "--pretend" not in myopts and myaction not in ("search","info"): + need_superuser = myaction in ('clean', 'depclean', 'deselect', + 'prune', 'unmerge') or not \ + (fetchonly or \ + (buildpkgonly and portage.data.secpass >= 1) or \ + myaction in ("metadata", "regen", "sync")) + if portage.data.secpass < 1 or \ + need_superuser: + if need_superuser: + access_desc = "superuser" + else: + access_desc = "portage group" + # Always show portage_group_warning() when only portage group + # access is required but the user is not in the portage group. + if "--ask" in myopts: + writemsg_stdout("This action requires %s access...\n" % \ + (access_desc,), noiselevel=-1) + if portage.data.secpass < 1 and not need_superuser: + portage.data.portage_group_warning() + if userquery("Would you like to add --pretend to options?", + "--ask-enter-invalid" in myopts) == "No": + return 128 + signal.SIGINT + myopts["--pretend"] = True + myopts.pop("--ask") + else: + sys.stderr.write(("emerge: %s access is required\n") \ + % access_desc) + if portage.data.secpass < 1 and not need_superuser: + portage.data.portage_group_warning() + return 1 + + # Disable emergelog for everything except build or unmerge operations. + # This helps minimize parallel emerge.log entries that can confuse log + # parsers like genlop. + disable_emergelog = False + for x in ("--pretend", "--fetchonly", "--fetch-all-uri"): + if x in myopts: + disable_emergelog = True + break + if disable_emergelog: + pass + elif myaction in ("search", "info"): + disable_emergelog = True + elif portage.data.secpass < 1: + disable_emergelog = True + + import _emerge.emergelog + _emerge.emergelog._disable = disable_emergelog + + if not disable_emergelog: + if 'EMERGE_LOG_DIR' in settings: + try: + # At least the parent needs to exist for the lock file. + portage.util.ensure_dirs(settings['EMERGE_LOG_DIR']) + except portage.exception.PortageException as e: + writemsg_level("!!! Error creating directory for " + \ + "EMERGE_LOG_DIR='%s':\n!!! %s\n" % \ + (settings['EMERGE_LOG_DIR'], e), + noiselevel=-1, level=logging.ERROR) + portage.util.ensure_dirs(_emerge.emergelog._emerge_log_dir) + else: + _emerge.emergelog._emerge_log_dir = settings["EMERGE_LOG_DIR"] + else: + _emerge.emergelog._emerge_log_dir = os.path.join(os.sep, + settings["EPREFIX"].lstrip(os.sep), "var", "log") + portage.util.ensure_dirs(_emerge.emergelog._emerge_log_dir) + + if not "--pretend" in myopts: + emergelog(xterm_titles, "Started emerge on: "+\ + _unicode_decode( + time.strftime("%b %d, %Y %H:%M:%S", time.localtime()), + encoding=_encodings['content'], errors='replace')) + myelogstr="" + if myopts: + opt_list = [] + for opt, arg in myopts.items(): + if arg is True: + opt_list.append(opt) + elif isinstance(arg, list): + # arguments like --exclude that use 'append' action + for x in arg: + opt_list.append("%s=%s" % (opt, x)) + else: + opt_list.append("%s=%s" % (opt, arg)) + myelogstr=" ".join(opt_list) + if myaction: + myelogstr += " --" + myaction + if myfiles: + myelogstr += " " + " ".join(oldargs) + emergelog(xterm_titles, " *** emerge " + myelogstr) + + oldargs = None + + def emergeexitsig(signum, frame): + signal.signal(signal.SIGTERM, signal.SIG_IGN) + portage.util.writemsg( + "\n\nExiting on signal %(signal)s\n" % {"signal":signum}) + sys.exit(128 + signum) + + signal.signal(signal.SIGTERM, emergeexitsig) + + def emergeexit(): + """This gets out final log message in before we quit.""" + if "--pretend" not in myopts: + emergelog(xterm_titles, " *** terminating.") + if xterm_titles: + xtermTitleReset() + portage.atexit_register(emergeexit) + + if myaction in ("config", "metadata", "regen", "sync"): + if "--pretend" in myopts: + sys.stderr.write(("emerge: The '%s' action does " + \ + "not support '--pretend'.\n") % myaction) + return 1 + + if "sync" == myaction: + return action_sync(settings, trees, mtimedb, myopts, myaction) + elif "metadata" == myaction: + action_metadata(settings, + trees[settings['EROOT']]['porttree'].dbapi, myopts) + elif myaction=="regen": + validate_ebuild_environment(trees) + return action_regen(settings, + trees[settings['EROOT']]['porttree'].dbapi, myopts.get("--jobs"), + myopts.get("--load-average")) + # HELP action + elif "config"==myaction: + validate_ebuild_environment(trees) + action_config(settings, trees, myopts, myfiles) + + # SEARCH action + elif "search"==myaction: + validate_ebuild_environment(trees) + action_search(trees[settings['EROOT']]['root_config'], + myopts, myfiles, spinner) + + elif myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge'): + validate_ebuild_environment(trees) + rval = action_uninstall(settings, trees, mtimedb["ldpath"], + myopts, myaction, myfiles, spinner) + if not (myaction == 'deselect' or + buildpkgonly or fetchonly or pretend): + post_emerge(myaction, myopts, myfiles, settings['EROOT'], + trees, mtimedb, rval) + return rval + + elif myaction == 'info': + + # Ensure atoms are valid before calling unmerge(). + vardb = trees[settings['EROOT']]['vartree'].dbapi + portdb = trees[settings['EROOT']]['porttree'].dbapi + bindb = trees[settings['EROOT']]["bintree"].dbapi + valid_atoms = [] + for x in myfiles: + if is_valid_package_atom(x, allow_repo=True): + try: + #look at the installed files first, if there is no match + #look at the ebuilds, since EAPI 4 allows running pkg_info + #on non-installed packages + valid_atom = dep_expand(x, mydb=vardb, settings=settings) + if valid_atom.cp.split("/")[0] == "null": + valid_atom = dep_expand(x, + mydb=portdb, settings=settings) + + if valid_atom.cp.split("/")[0] == "null" and \ + "--usepkg" in myopts: + valid_atom = dep_expand(x, + mydb=bindb, settings=settings) + + valid_atoms.append(valid_atom) + + except portage.exception.AmbiguousPackageName as 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.args[0]: + writemsg_level(" %s\n" % colorize("INFORM", i), + level=logging.ERROR, noiselevel=-1) + writemsg_level("\n", level=logging.ERROR, noiselevel=-1) + return 1 + 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 + + return action_info(settings, trees, myopts, valid_atoms) + + # "update", "system", or just process files: + else: + validate_ebuild_environment(trees) + + for x in myfiles: + if x.startswith(SETPREFIX) or \ + is_valid_package_atom(x, allow_repo=True): + continue + if x[:1] == os.sep: + continue + try: + os.lstat(x) + continue + except OSError: + pass + 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 + + # GLEP 42 says to display news *after* an emerge --pretend + if "--pretend" not in myopts: + display_news_notification(root_config, myopts) + retval = action_build(settings, trees, mtimedb, + myopts, myaction, myfiles, spinner) + post_emerge(myaction, myopts, myfiles, settings['EROOT'], + trees, mtimedb, retval) + + return retval -- cgit v1.2.3-1-g7c22