# Copyright 1999-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import argparse import locale import platform import sys import portage portage.proxy.lazyimport.lazyimport(globals(), 'logging', 'portage.dep:Atom', 'portage.util:writemsg_level', 'textwrap', '_emerge.actions:load_emerge_config,run_action,' + \ 'validate_ebuild_environment', '_emerge.help:help@emerge_help', '_emerge.is_valid_package_atom:insert_category_into_atom' ) from portage import os from portage.sync import _SUBMODULE_PATH_MAP if sys.hexversion >= 0x3000000: long = int options=[ "--alphabetical", "--ask-enter-invalid", "--buildpkgonly", "--changed-use", "--changelog", "--columns", "--debug", "--digest", "--emptytree", "--verbose-conflicts", "--fetchonly", "--fetch-all-uri", "--ignore-default-opts", "--noconfmem", "--newrepo", "--newuse", "--nodeps", "--noreplace", "--nospinner", "--oneshot", "--onlydeps", "--pretend", "--quiet-repo-display", "--quiet-unmerge-warn", "--resume", "--searchdesc", "--skipfirst", "--tree", "--unordered-display", "--update", ] shortmapping={ "1":"--oneshot", "B":"--buildpkgonly", "c":"--depclean", "C":"--unmerge", "d":"--debug", "e":"--emptytree", "f":"--fetchonly", "F":"--fetch-all-uri", "h":"--help", "l":"--changelog", "n":"--noreplace", "N":"--newuse", "o":"--onlydeps", "O":"--nodeps", "p":"--pretend", "P":"--prune", "r":"--resume", "s":"--search", "S":"--searchdesc", "t":"--tree", "u":"--update", "U":"--changed-use", "V":"--version" } COWSAY_MOO = r""" Larry loves Gentoo (%s) _______________________ < Have you mooed today? > ----------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || """ def multiple_actions(action1, action2): sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n") sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2)) sys.exit(1) def insert_optional_args(args): """ Parse optional arguments and insert a value if one has not been provided. This is done before feeding the args to the optparse parser since that parser does not support this feature natively. """ class valid_integers(object): def __contains__(self, s): try: return int(s) >= 0 except (ValueError, OverflowError): return False valid_integers = valid_integers() class valid_floats(object): def __contains__(self, s): try: return float(s) >= 0 except (ValueError, OverflowError): return False valid_floats = valid_floats() y_or_n = ('y', 'n',) new_args = [] default_arg_opts = { '--alert' : y_or_n, '--ask' : y_or_n, '--autounmask' : y_or_n, '--autounmask-continue' : y_or_n, '--autounmask-only' : y_or_n, '--autounmask-keep-keywords' : y_or_n, '--autounmask-keep-masks': y_or_n, '--autounmask-unrestricted-atoms' : y_or_n, '--autounmask-write' : y_or_n, '--binpkg-changed-deps' : y_or_n, '--buildpkg' : y_or_n, '--changed-deps' : y_or_n, '--changed-slot' : y_or_n, '--changed-deps-report' : y_or_n, '--complete-graph' : y_or_n, '--deep' : valid_integers, '--depclean-lib-check' : y_or_n, '--deselect' : y_or_n, '--binpkg-respect-use' : y_or_n, '--fail-clean' : y_or_n, '--fuzzy-search' : y_or_n, '--getbinpkg' : y_or_n, '--getbinpkgonly' : y_or_n, '--ignore-world' : y_or_n, '--jobs' : valid_integers, '--keep-going' : y_or_n, '--load-average' : valid_floats, '--onlydeps-with-rdeps' : y_or_n, '--package-moves' : y_or_n, '--quiet' : y_or_n, '--quiet-build' : y_or_n, '--quiet-fail' : y_or_n, '--read-news' : y_or_n, '--rebuild-if-new-slot': y_or_n, '--rebuild-if-new-rev' : y_or_n, '--rebuild-if-new-ver' : y_or_n, '--rebuild-if-unbuilt' : y_or_n, '--rebuilt-binaries' : y_or_n, '--root-deps' : ('rdeps',), '--select' : y_or_n, '--selective' : y_or_n, "--use-ebuild-visibility": y_or_n, '--usepkg' : y_or_n, '--usepkgonly' : y_or_n, '--verbose' : y_or_n, '--verbose-slot-rebuilds': y_or_n, '--with-test-deps' : y_or_n, } short_arg_opts = { 'D' : valid_integers, 'j' : valid_integers, } # Don't make things like "-kn" expand to "-k n" # since existence of -n makes it too ambiguous. short_arg_opts_n = { 'a' : y_or_n, 'A' : y_or_n, 'b' : y_or_n, 'g' : y_or_n, 'G' : y_or_n, 'k' : y_or_n, 'K' : y_or_n, 'q' : y_or_n, 'v' : y_or_n, 'w' : y_or_n, } arg_stack = args[:] arg_stack.reverse() while arg_stack: arg = arg_stack.pop() default_arg_choices = default_arg_opts.get(arg) if default_arg_choices is not None: new_args.append(arg) if arg_stack and arg_stack[-1] in default_arg_choices: new_args.append(arg_stack.pop()) else: # insert default argument new_args.append('True') continue if arg[:1] != "-" or arg[:2] == "--": new_args.append(arg) continue match = None for k, arg_choices in short_arg_opts.items(): if k in arg: match = k break if match is None: for k, arg_choices in short_arg_opts_n.items(): 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("-" + match) opt_arg = None saved_opts = None if arg[1:2] == match: if match not in short_arg_opts_n and arg[2:] in arg_choices: opt_arg = arg[2:] else: saved_opts = arg[2:] opt_arg = "True" else: saved_opts = arg[1:].replace(match, "") opt_arg = "True" 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(opt_arg) if saved_opts is not None: # Recycle these on arg_stack since they # might contain another match. arg_stack.append("-" + saved_opts) return new_args def _find_bad_atoms(atoms, less_strict=False): """ Declares all atoms as invalid that have an operator, a use dependency, a blocker or a repo spec. It accepts atoms with wildcards. In less_strict mode it accepts operators and repo specs. """ bad_atoms = [] for x in ' '.join(atoms).split(): atom = x if "/" not in x.split(":")[0]: x_cat = insert_category_into_atom(x, 'dummy-category') if x_cat is not None: atom = x_cat bad_atom = False try: atom = Atom(atom, allow_wildcard=True, allow_repo=less_strict) except portage.exception.InvalidAtom: bad_atom = True if bad_atom or (atom.operator and not less_strict) or atom.blocker or atom.use: bad_atoms.append(x) return bad_atoms def parse_opts(tmpcmdline, silent=False): myaction=None myopts = {} actions = frozenset([ "clean", "check-news", "config", "depclean", "help", "info", "list-sets", "metadata", "moo", "prune", "rage-clean", "regen", "search", "sync", "unmerge", "version", ]) longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} y_or_n = ("y", "n") true_y_or_n = ("True", "y", "n") true_y = ("True", "y") argument_options = { "--alert": { "shortopt" : "-A", "help" : "alert (terminal bell) on prompts", "choices" : true_y_or_n }, "--ask": { "shortopt" : "-a", "help" : "prompt before performing any actions", "choices" : true_y_or_n }, "--autounmask": { "help" : "automatically unmask packages", "choices" : true_y_or_n }, "--autounmask-backtrack": { "help": ("continue backtracking when there are autounmask " "configuration changes"), "choices":("y", "n") }, "--autounmask-continue": { "help" : "write autounmask changes and continue", "choices" : true_y_or_n }, "--autounmask-only": { "help" : "only perform --autounmask", "choices" : true_y_or_n }, "--autounmask-license": { "help" : "allow autounmask to change package.license", "choices" : y_or_n }, "--autounmask-unrestricted-atoms": { "help" : "write autounmask changes with >= atoms if possible", "choices" : true_y_or_n }, "--autounmask-use": { "help" : "allow autounmask to change package.use", "choices" : y_or_n }, "--autounmask-keep-keywords": { "help" : "don't add package.accept_keywords entries", "choices" : true_y_or_n }, "--autounmask-keep-masks": { "help" : "don't add package.unmask entries", "choices" : true_y_or_n }, "--autounmask-write": { "help" : "write changes made by --autounmask to disk", "choices" : true_y_or_n }, "--accept-properties": { "help":"temporarily override ACCEPT_PROPERTIES", "action":"store" }, "--accept-restrict": { "help":"temporarily override ACCEPT_RESTRICT", "action":"store" }, "--backtrack": { "help" : "Specifies how many times to backtrack if dependency " + \ "calculation fails ", "action" : "store" }, "--binpkg-changed-deps": { "help" : ("reject binary packages with outdated " "dependencies"), "choices" : true_y_or_n }, "--buildpkg": { "shortopt" : "-b", "help" : "build binary packages", "choices" : true_y_or_n }, "--buildpkg-exclude": { "help" :"A space separated list of package atoms for which " + \ "no binary packages should be built. This option overrides all " + \ "possible ways to enable building of binary packages.", "action" : "append" }, "--changed-deps": { "help" : ("replace installed packages with " "outdated dependencies"), "choices" : true_y_or_n }, "--changed-deps-report": { "help" : ("report installed packages with " "outdated dependencies"), "choices" : true_y_or_n }, "--changed-slot": { "help" : ("replace installed packages with " "outdated SLOT metadata"), "choices" : true_y_or_n }, "--config-root": { "help":"specify the location for portage configuration files", "action":"store" }, "--color": { "help":"enable or disable color output", "choices":("y", "n") }, "--complete-graph": { "help" : "completely account for all known dependencies", "choices" : true_y_or_n }, "--complete-graph-if-new-use": { "help" : "trigger --complete-graph behavior if USE or IUSE will change for an installed package", "choices" : y_or_n }, "--complete-graph-if-new-ver": { "help" : "trigger --complete-graph behavior if an installed package version will change (upgrade or downgrade)", "choices" : y_or_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" }, "--depclean-lib-check": { "help" : "check for consumers of libraries before removing them", "choices" : true_y_or_n }, "--deselect": { "help" : "remove atoms/sets from the world file", "choices" : true_y_or_n }, "--dynamic-deps": { "help": "substitute the dependencies of installed packages with the dependencies of unbuilt ebuilds", "choices": y_or_n }, "--exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge won't install any ebuild or binary package that " + \ "matches any of the given package atoms.", "action" : "append" }, "--fail-clean": { "help" : "clean temp files after build failure", "choices" : true_y_or_n }, "--fuzzy-search": { "help": "Enable or disable fuzzy search", "choices": true_y_or_n }, "--ignore-built-slot-operator-deps": { "help": "Ignore the slot/sub-slot := operator parts of dependencies that have " "been recorded when packages where built. This option is intended " "only for debugging purposes, and it only affects built packages " "that specify slot/sub-slot := operator dependencies using the " "experimental \"4-slot-abi\" EAPI.", "choices": y_or_n }, "--ignore-soname-deps": { "help": "Ignore the soname dependencies of binary and " "installed packages. This option is enabled by " "default, since soname dependencies are relatively " "new, and the required metadata is not guaranteed to " "exist for binary and installed packages built with " "older versions of portage.", "choices": y_or_n }, "--ignore-world": { "help" : "ignore the @world package set and its dependencies", "choices" : true_y_or_n }, "--implicit-system-deps": { "help": "Assume that packages may have implicit dependencies on" "packages which belong to the @system set", "choices": y_or_n }, "--jobs": { "shortopt" : "-j", "help" : "Specifies the number of packages to build " + \ "simultaneously.", "action" : "store" }, "--keep-going": { "help" : "continue as much as possible after an error", "choices" : true_y_or_n }, "--load-average": { "help" :"Specifies that no new builds should be started " + \ "if there are other builds running and the load average " + \ "is at least LOAD (a floating-point number).", "action" : "store" }, "--misspell-suggestions": { "help" : "enable package name misspell suggestions", "choices" : ("y", "n") }, "--with-bdeps": { "help":"include unnecessary build time dependencies", "choices":("y", "n") }, "--with-bdeps-auto": { "help":("automatically enable --with-bdeps for installation" " actions, unless --usepkg is enabled"), "choices":("y", "n") }, "--reinstall": { "help":"specify conditions to trigger package reinstallation", "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", "choices" : true_y_or_n }, "--getbinpkg": { "shortopt" : "-g", "help" : "fetch binary packages", "choices" : true_y_or_n }, "--getbinpkgonly": { "shortopt" : "-G", "help" : "fetch binary packages only", "choices" : true_y_or_n }, "--usepkg-exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will ignore matching binary packages. ", "action" : "append", }, "--onlydeps-with-rdeps": { "help" : "modify interpretation of depedencies", "choices" : true_y_or_n }, "--rebuild-exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will not rebuild these packages due to the " + \ "--rebuild flag. ", "action" : "append", }, "--rebuild-ignore": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will not rebuild packages that depend on matching " + \ "packages due to the --rebuild flag. ", "action" : "append", }, "--package-moves": { "help" : "perform package moves when necessary", "choices" : true_y_or_n }, "--prefix": { "help" : "specify the installation prefix", "action" : "store" }, "--pkg-format": { "help" : "format of result binary package", "action" : "store", }, "--quickpkg-direct": { "help": "Enable use of installed packages directly as binary packages", "choices": y_or_n }, "--quiet": { "shortopt" : "-q", "help" : "reduced or condensed output", "choices" : true_y_or_n }, "--quiet-build": { "help" : "redirect build output to logs", "choices" : true_y_or_n, }, "--quiet-fail": { "help" : "suppresses display of the build log on stdout", "choices" : true_y_or_n, }, "--read-news": { "help" : "offer to read unread news via eselect", "choices" : true_y_or_n }, "--rebuild-if-new-slot": { "help" : ("Automatically rebuild or reinstall packages when slot/sub-slot := " "operator dependencies can be satisfied by a newer slot, so that " "older packages slots will become eligible for removal by the " "--depclean action as soon as possible."), "choices" : true_y_or_n }, "--rebuild-if-new-rev": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built, " + \ "if the dependency is not already installed with the " + \ "same version and revision.", "choices" : true_y_or_n }, "--rebuild-if-new-ver": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built, " + \ "if the dependency is not already installed with the " + \ "same version. Revision numbers are ignored.", "choices" : true_y_or_n }, "--rebuild-if-unbuilt": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built.", "choices" : true_y_or_n }, "--rebuilt-binaries": { "help" : "replace installed packages with binary " + \ "packages that have been rebuilt", "choices" : true_y_or_n }, "--rebuilt-binaries-timestamp": { "help" : "use only binaries that are newer than this " + \ "timestamp for --rebuilt-binaries", "action" : "store" }, "--root": { "help" : "specify the target root filesystem for merging packages", "action" : "store" }, "--root-deps": { "help" : "modify interpretation of depedencies", "choices" :("True", "rdeps") }, "--search-index": { "help": "Enable or disable indexed search (enabled by default)", "choices": y_or_n }, "--search-similarity": { "help": ("Set minimum similarity percentage for fuzzy seach " "(a floating-point number between 0 and 100)"), "action": "store" }, "--select": { "shortopt" : "-w", "help" : "add specified packages to the world set " + \ "(inverse of --oneshot)", "choices" : true_y_or_n }, "--selective": { "help" : "identical to --noreplace", "choices" : true_y_or_n }, "--sync-submodule": { "help" : ("Restrict sync to the specified submodule(s)." " (--sync action only)"), "choices" : tuple(_SUBMODULE_PATH_MAP), "action" : "append", }, "--sysroot": { "help":"specify the location for build dependencies specified in DEPEND", "action":"store" }, "--use-ebuild-visibility": { "help" : "use unbuilt ebuild metadata for visibility checks on built packages", "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", "choices" : true_y_or_n }, "--usepkgonly": { "shortopt" : "-K", "help" : "use only binary packages", "choices" : true_y_or_n }, "--verbose": { "shortopt" : "-v", "help" : "verbose output", "choices" : true_y_or_n }, "--verbose-slot-rebuilds": { "help" : "verbose slot rebuild output", "choices" : true_y_or_n }, "--with-test-deps": { "help" : "pull in test deps for packages " + \ "matched by arguments", "choices" : true_y_or_n }, } parser = argparse.ArgumentParser(add_help=False) for action_opt in actions: parser.add_argument("--" + action_opt, action="store_true", dest=action_opt.replace("-", "_"), default=False) for myopt in options: parser.add_argument(myopt, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for shortopt, longopt in shortmapping.items(): parser.add_argument("-" + shortopt, action="store_true", dest=longopt.lstrip("--").replace("-", "_"), default=False) for myalias, myopt in longopt_aliases.items(): parser.add_argument(myalias, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for myopt, kwargs in argument_options.items(): shortopt = kwargs.pop("shortopt", None) args = [myopt] if shortopt is not None: args.append(shortopt) parser.add_argument(dest=myopt.lstrip("--").replace("-", "_"), *args, **kwargs) parser.add_argument('positional_args', nargs='*') tmpcmdline = insert_optional_args(tmpcmdline) myoptions = parser.parse_args(args=tmpcmdline) if myoptions.alert in true_y: myoptions.alert = True else: myoptions.alert = None if myoptions.ask in true_y: myoptions.ask = True else: myoptions.ask = None if myoptions.autounmask in true_y: myoptions.autounmask = True if myoptions.autounmask_continue in true_y: myoptions.autounmask_continue = True if myoptions.autounmask_only in true_y: myoptions.autounmask_only = True else: myoptions.autounmask_only = None if myoptions.autounmask_unrestricted_atoms in true_y: myoptions.autounmask_unrestricted_atoms = True if myoptions.autounmask_keep_keywords in true_y: myoptions.autounmask_keep_keywords = True if myoptions.autounmask_keep_masks in true_y: myoptions.autounmask_keep_masks = True if myoptions.autounmask_write in true_y: myoptions.autounmask_write = True if myoptions.binpkg_changed_deps is not None: if myoptions.binpkg_changed_deps in true_y: myoptions.binpkg_changed_deps = 'y' else: myoptions.binpkg_changed_deps = 'n' if myoptions.buildpkg in true_y: myoptions.buildpkg = True if myoptions.buildpkg_exclude: bad_atoms = _find_bad_atoms(myoptions.buildpkg_exclude, less_strict=True) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --buildpkg-exclude parameter: '%s'\n" % \ (",".join(bad_atoms),)) if myoptions.changed_deps is not None: if myoptions.changed_deps in true_y: myoptions.changed_deps = 'y' else: myoptions.changed_deps = 'n' if myoptions.changed_deps_report is not None: if myoptions.changed_deps_report in true_y: myoptions.changed_deps_report = 'y' else: myoptions.changed_deps_report = 'n' if myoptions.changed_slot is not None: if myoptions.changed_slot in true_y: myoptions.changed_slot = True else: myoptions.changed_slot = None if myoptions.changed_use is not False: myoptions.reinstall = "changed-use" myoptions.changed_use = False if myoptions.deselect in true_y: myoptions.deselect = True if myoptions.binpkg_respect_use is not None: if myoptions.binpkg_respect_use in true_y: myoptions.binpkg_respect_use = 'y' else: myoptions.binpkg_respect_use = 'n' if myoptions.complete_graph in true_y: myoptions.complete_graph = True else: myoptions.complete_graph = None if myoptions.depclean_lib_check in true_y: myoptions.depclean_lib_check = True if myoptions.exclude: 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.rebuild_exclude: bad_atoms = _find_bad_atoms(myoptions.rebuild_exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --rebuild-exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.rebuild_ignore: bad_atoms = _find_bad_atoms(myoptions.rebuild_ignore) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --rebuild-ignore parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.usepkg_exclude: bad_atoms = _find_bad_atoms(myoptions.usepkg_exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --usepkg-exclude 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 if myoptions.fuzzy_search in true_y: myoptions.fuzzy_search = True if myoptions.getbinpkg in true_y: myoptions.getbinpkg = True else: myoptions.getbinpkg = None if myoptions.getbinpkgonly in true_y: myoptions.getbinpkgonly = True else: myoptions.getbinpkgonly = None if myoptions.ignore_world in true_y: myoptions.ignore_world = True if myoptions.keep_going in true_y: myoptions.keep_going = True else: myoptions.keep_going = None if myoptions.package_moves in true_y: myoptions.package_moves = True if myoptions.quiet in true_y: myoptions.quiet = True else: myoptions.quiet = None if myoptions.quiet_build in true_y: myoptions.quiet_build = 'y' if myoptions.quiet_fail in true_y: myoptions.quiet_fail = 'y' if myoptions.read_news in true_y: myoptions.read_news = True else: myoptions.read_news = None if myoptions.rebuild_if_new_slot in true_y: myoptions.rebuild_if_new_slot = 'y' if myoptions.rebuild_if_new_ver in true_y: myoptions.rebuild_if_new_ver = True else: myoptions.rebuild_if_new_ver = None if myoptions.rebuild_if_new_rev in true_y: myoptions.rebuild_if_new_rev = True myoptions.rebuild_if_new_ver = None else: myoptions.rebuild_if_new_rev = None if myoptions.rebuild_if_unbuilt in true_y: myoptions.rebuild_if_unbuilt = True myoptions.rebuild_if_new_rev = None myoptions.rebuild_if_new_ver = None else: myoptions.rebuild_if_unbuilt = None if myoptions.rebuilt_binaries in true_y: myoptions.rebuilt_binaries = True if myoptions.root_deps in true_y: myoptions.root_deps = True if myoptions.select in true_y: myoptions.select = True myoptions.oneshot = False elif myoptions.select == "n": myoptions.oneshot = True if myoptions.selective in true_y: myoptions.selective = True if myoptions.backtrack is not None: try: backtrack = int(myoptions.backtrack) except (OverflowError, ValueError): backtrack = -1 if backtrack < 0: backtrack = None if not silent: parser.error("Invalid --backtrack parameter: '%s'\n" % \ (myoptions.backtrack,)) myoptions.backtrack = backtrack 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: parser.error("Invalid --deep parameter: '%s'\n" % \ (myoptions.deep,)) myoptions.deep = deep if myoptions.jobs: jobs = None if myoptions.jobs == "True": jobs = True else: try: jobs = int(myoptions.jobs) except ValueError: jobs = -1 if jobs is not True and \ jobs < 1: jobs = None if not silent: parser.error("Invalid --jobs parameter: '%s'\n" % \ (myoptions.jobs,)) myoptions.jobs = jobs if myoptions.load_average == "True": myoptions.load_average = None if myoptions.load_average: try: load_average = float(myoptions.load_average) except ValueError: load_average = 0.0 if load_average <= 0.0: load_average = None if not silent: parser.error("Invalid --load-average parameter: '%s'\n" % \ (myoptions.load_average,)) myoptions.load_average = load_average if myoptions.rebuilt_binaries_timestamp: try: rebuilt_binaries_timestamp = int(myoptions.rebuilt_binaries_timestamp) except ValueError: rebuilt_binaries_timestamp = -1 if rebuilt_binaries_timestamp < 0: rebuilt_binaries_timestamp = 0 if not silent: parser.error("Invalid --rebuilt-binaries-timestamp parameter: '%s'\n" % \ (myoptions.rebuilt_binaries_timestamp,)) myoptions.rebuilt_binaries_timestamp = rebuilt_binaries_timestamp if myoptions.search_similarity: try: search_similarity = float(myoptions.search_similarity) except ValueError: parser.error("Invalid --search-similarity parameter " "(not a number): '{}'\n".format( myoptions.search_similarity)) if search_similarity < 0 or search_similarity > 100: parser.error("Invalid --search-similarity parameter " "(not between 0 and 100): '{}'\n".format( myoptions.search_similarity)) myoptions.search_similarity = search_similarity if myoptions.use_ebuild_visibility in true_y: myoptions.use_ebuild_visibility = True else: # None or "n" pass if myoptions.usepkg in true_y: myoptions.usepkg = True else: myoptions.usepkg = None if myoptions.usepkgonly in true_y: myoptions.usepkgonly = True else: myoptions.usepkgonly = None if myoptions.verbose in true_y: myoptions.verbose = True else: myoptions.verbose = None if myoptions.with_test_deps in true_y: myoptions.with_test_deps = True else: myoptions.with_test_deps = None for myopt in options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) if v: myopts[myopt] = True for myopt in argument_options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) if v is not None: myopts[myopt] = v if myoptions.searchdesc: myoptions.search = True for action_opt in actions: v = getattr(myoptions, action_opt.replace("-", "_")) if v: if myaction: multiple_actions(myaction, action_opt) sys.exit(1) myaction = action_opt if myaction is None and myoptions.deselect is True: myaction = 'deselect' return myaction, myopts, myoptions.positional_args def profile_check(trees, myaction): if myaction in ("help", "info", "search", "sync", "version"): return os.EX_OK for root_trees in trees.values(): if (root_trees["root_config"].settings.profiles and 'ARCH' in root_trees["root_config"].settings): continue # generate some profile related warning messages validate_ebuild_environment(trees) msg = ("Your current profile is invalid. If you have just changed " "your profile configuration, you should revert back to the " "previous configuration. Allowed actions are limited to " "--help, --info, --search, --sync, and --version.") writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)), level=logging.ERROR, noiselevel=-1) return 1 return os.EX_OK def emerge_main(args=None): """ @param args: command arguments (default: sys.argv[1:]) @type args: list """ if args is None: args = sys.argv[1:] args = portage._decode_argv(args) # Use system locale. try: locale.setlocale(locale.LC_ALL, "") except locale.Error as e: writemsg_level("setlocale: %s\n" % e, level=logging.WARN) # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(args, silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--sysroot" in myopts: os.environ["SYSROOT"] = myopts["--sysroot"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--prefix" in myopts: os.environ["EPREFIX"] = myopts["--prefix"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] if "--accept-restrict" in myopts: os.environ["ACCEPT_RESTRICT"] = myopts["--accept-restrict"] # optimize --help (no need to load config / EMERGE_DEFAULT_OPTS) if myaction == "help": emerge_help() return os.EX_OK elif myaction == "moo": print(COWSAY_MOO % platform.system()) return os.EX_OK elif myaction == "sync": # need to set this to True now in order for the repository config # loading to allow new repos with non-existent directories portage._sync_mode = True # Verify that /dev/null exists and is a device file as a cheap early # filter for obviously broken /dev/s. try: if os.stat(os.devnull).st_rdev == 0: writemsg_level("Failed to validate a sane '/dev'.\n" "'/dev/null' is not a device file.\n", level=logging.ERROR, noiselevel=-1) return 1 except OSError: writemsg_level("Failed to validate a sane '/dev'.\n" "'/dev/null' does not exist.\n", level=logging.ERROR, noiselevel=-1) return 1 # Verify that BASH process substitution works as another cheap early # filter. Process substitution uses '/dev/fd'. with open(os.devnull, 'r+b') as dev_null: fd_pipes = { 0: dev_null.fileno(), 1: dev_null.fileno(), 2: dev_null.fileno(), } if portage.process.spawn_bash("[[ $(< <(echo foo) ) == foo ]]", fd_pipes=fd_pipes) != 0: writemsg_level("Failed to validate a sane '/dev'.\n" "bash process substitution doesn't work; this may be an " "indication of a broken '/dev/fd'.\n", level=logging.ERROR, noiselevel=-1) return 1 # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) emerge_config = load_emerge_config( action=myaction, args=myfiles, opts=myopts) # Make locale variables from configuration files (make.defaults, make.conf) affect locale of emerge process. for locale_var_name in ("LANGUAGE", "LC_ALL", "LC_ADDRESS", "LC_COLLATE", "LC_CTYPE", "LC_IDENTIFICATION", "LC_MEASUREMENT", "LC_MESSAGES", "LC_MONETARY", "LC_NAME", "LC_NUMERIC", "LC_PAPER", "LC_TELEPHONE", "LC_TIME", "LANG"): locale_var_value = emerge_config.running_config.settings.get(locale_var_name) if locale_var_value is not None: os.environ.setdefault(locale_var_name, locale_var_value) try: locale.setlocale(locale.LC_ALL, "") except locale.Error as e: writemsg_level("setlocale: %s\n" % e, level=logging.WARN) tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend(portage.util.shlex_split( emerge_config.target_config.settings.get( "EMERGE_DEFAULT_OPTS", ""))) tmpcmdline.extend(args) emerge_config.action, emerge_config.opts, emerge_config.args = \ parse_opts(tmpcmdline) try: return run_action(emerge_config) finally: # Call destructors for our portdbapi instances. for x in emerge_config.trees.values(): if "porttree" in x.lazy_items: continue x["porttree"].dbapi.close_caches()