1 # Copyright 1999-2009 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 from __future__ import print_function
13 from subprocess import getstatusoutput as subprocess_getstatusoutput
15 from commands import getstatusoutput as subprocess_getstatusoutput
17 from portage import os
18 from portage import _encodings
19 from portage import _unicode_decode
21 import portage.xpak, errno, re, time
22 from portage.output import colorize, xtermTitle, xtermTitleReset
23 from portage.output import create_color_func
24 good = create_color_func("GOOD")
25 bad = create_color_func("BAD")
29 portage.dep._dep_check_strict = True
32 import portage.exception
33 from portage.data import secpass
34 from portage.dbapi.dep_expand import dep_expand
35 from portage.util import normalize_path as normpath
36 from portage.util import writemsg, writemsg_level, writemsg_stdout
37 from portage.sets import SETPREFIX
38 from portage._global_updates import _global_updates
40 from _emerge.actions import action_config, action_sync, action_metadata, \
41 action_regen, action_search, action_uninstall, action_info, action_build, \
42 adjust_configs, chk_updated_cfg_files, display_missing_pkg_set, \
43 display_news_notification, getportageversion, load_emerge_config
45 from _emerge.emergelog import emergelog
46 from _emerge._flush_elog_mod_echo import _flush_elog_mod_echo
47 from _emerge.is_valid_package_atom import is_valid_package_atom
48 from _emerge.stdout_spinner import stdout_spinner
50 if sys.hexversion >= 0x3000000:
54 "--ask", "--alphabetical",
55 "--ask-enter-invalid",
56 "--buildpkg", "--buildpkgonly",
58 "--changelog", "--columns",
62 "--fetchonly", "--fetch-all-uri",
63 "--ignore-default-opts",
66 "--nodeps", "--noreplace",
67 "--nospinner", "--oneshot",
68 "--onlydeps", "--pretend",
71 "--quiet-unmerge-warn",
76 "--unordered-display",
84 "b":"--buildpkg", "B":"--buildpkgonly",
89 "f":"--fetchonly", "F":"--fetch-all-uri",
92 "n":"--noreplace", "N":"--newuse",
93 "o":"--onlydeps", "O":"--nodeps",
94 "p":"--pretend", "P":"--prune",
97 "s":"--search", "S":"--searchdesc",
100 "v":"--verbose", "V":"--version"
103 def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
105 if os.path.exists("/usr/bin/install-info"):
106 out = portage.output.EOutput()
111 inforoot=normpath(root+z)
112 if os.path.isdir(inforoot):
113 infomtime = os.stat(inforoot)[stat.ST_MTIME]
114 if inforoot not in prev_mtimes or \
115 prev_mtimes[inforoot] != infomtime:
116 regen_infodirs.append(inforoot)
118 if not regen_infodirs:
119 portage.writemsg_stdout("\n")
120 out.einfo("GNU info directory index is up-to-date.")
122 portage.writemsg_stdout("\n")
123 out.einfo("Regenerating GNU info directory index...")
125 dir_extensions = ("", ".gz", ".bz2")
129 for inforoot in regen_infodirs:
133 if not os.path.isdir(inforoot) or \
134 not os.access(inforoot, os.W_OK):
137 file_list = os.listdir(inforoot)
139 dir_file = os.path.join(inforoot, "dir")
140 moved_old_dir = False
143 if x.startswith(".") or \
144 os.path.isdir(os.path.join(inforoot, x)):
146 if x.startswith("dir"):
148 for ext in dir_extensions:
149 if x == "dir" + ext or \
150 x == "dir" + ext + ".old":
155 if processed_count == 0:
156 for ext in dir_extensions:
158 os.rename(dir_file + ext, dir_file + ext + ".old")
160 except EnvironmentError as e:
161 if e.errno != errno.ENOENT:
165 myso=subprocess_getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1]
166 existsstr="already exists, for file `"
168 if re.search(existsstr,myso):
169 # Already exists... Don't increment the count for this.
171 elif myso[:44]=="install-info: warning: no info dir entry in ":
172 # This info file doesn't contain a DIR-header: install-info produces this
173 # (harmless) warning (the --quiet switch doesn't seem to work).
174 # Don't increment the count for this.
178 errmsg += myso + "\n"
181 if moved_old_dir and not os.path.exists(dir_file):
182 # We didn't generate a new dir file, so put the old file
183 # back where it was originally found.
184 for ext in dir_extensions:
186 os.rename(dir_file + ext + ".old", dir_file + ext)
187 except EnvironmentError as e:
188 if e.errno != errno.ENOENT:
192 # Clean dir.old cruft so that they don't prevent
193 # unmerge of otherwise empty directories.
194 for ext in dir_extensions:
196 os.unlink(dir_file + ext + ".old")
197 except EnvironmentError as e:
198 if e.errno != errno.ENOENT:
202 #update mtime so we can potentially avoid regenerating.
203 prev_mtimes[inforoot] = os.stat(inforoot)[stat.ST_MTIME]
206 out.eerror("Processed %d info files; %d errors." % \
208 writemsg_level(errmsg, level=logging.ERROR, noiselevel=-1)
211 out.einfo("Processed %d info files." % (icount,))
213 def display_preserved_libs(vardbapi, myopts):
216 # Ensure the registry is consistent with existing files.
217 vardbapi.plib_registry.pruneNonExisting()
219 if vardbapi.plib_registry.hasEntries():
220 if "--quiet" in myopts:
222 print(colorize("WARN", "!!!") + " existing preserved libs found")
226 print(colorize("WARN", "!!!") + " existing preserved libs:")
228 plibdata = vardbapi.plib_registry.getPreservedLibs()
229 linkmap = vardbapi.linkmap
232 linkmap_broken = False
236 except portage.exception.CommandNotFound as e:
237 writemsg_level("!!! Command Not Found: %s\n" % (e,),
238 level=logging.ERROR, noiselevel=-1)
240 linkmap_broken = True
242 search_for_owners = set()
244 internal_plib_keys = set(linkmap._obj_key(f) \
245 for f in plibdata[cpv])
246 for f in plibdata[cpv]:
247 if f in consumer_map:
250 for c in linkmap.findConsumers(f):
251 # Filter out any consumers that are also preserved libs
252 # belonging to the same package as the provider.
253 if linkmap._obj_key(c) not in internal_plib_keys:
256 consumer_map[f] = consumers
257 search_for_owners.update(consumers[:MAX_DISPLAY+1])
259 owners = vardbapi._owners.getFileOwnerMap(search_for_owners)
262 print(colorize("WARN", ">>>") + " package: %s" % cpv)
264 for f in plibdata[cpv]:
265 obj_key = linkmap._obj_key(f)
266 alt_paths = samefile_map.get(obj_key)
267 if alt_paths is None:
269 samefile_map[obj_key] = alt_paths
272 for alt_paths in samefile_map.values():
273 alt_paths = sorted(alt_paths)
275 print(colorize("WARN", " * ") + " - %s" % (p,))
277 consumers = consumer_map.get(f, [])
278 for c in consumers[:MAX_DISPLAY]:
279 print(colorize("WARN", " * ") + " used by %s (%s)" % \
280 (c, ", ".join(x.mycpv for x in owners.get(c, []))))
281 if len(consumers) == MAX_DISPLAY + 1:
282 print(colorize("WARN", " * ") + " used by %s (%s)" % \
283 (consumers[MAX_DISPLAY], ", ".join(x.mycpv \
284 for x in owners.get(consumers[MAX_DISPLAY], []))))
285 elif len(consumers) > MAX_DISPLAY:
286 print(colorize("WARN", " * ") + " used by %d other files" % (len(consumers) - MAX_DISPLAY))
287 print("Use " + colorize("GOOD", "emerge @preserved-rebuild") + " to rebuild packages using these libraries")
289 def post_emerge(root_config, myopts, mtimedb, retval):
291 Misc. things to run at the end of a merge session.
297 Display preserved libs warnings
300 @param trees: A dictionary mapping each ROOT to it's package databases
302 @param mtimedb: The mtimeDB to store data needed across merge invocations
303 @type mtimedb: MtimeDB class instance
304 @param retval: Emerge's return value
308 1. Calls sys.exit(retval)
311 target_root = root_config.root
312 trees = { target_root : root_config.trees }
313 vardbapi = trees[target_root]["vartree"].dbapi
314 settings = vardbapi.settings
315 info_mtimes = mtimedb["info"]
317 # Load the most current variables from ${ROOT}/etc/profile.env
320 settings.regenerate()
323 config_protect = settings.get("CONFIG_PROTECT","").split()
324 infodirs = settings.get("INFOPATH","").split(":") + \
325 settings.get("INFODIR","").split(":")
329 if retval == os.EX_OK:
330 exit_msg = " *** exiting successfully."
332 exit_msg = " *** exiting unsuccessfully with status '%s'." % retval
333 emergelog("notitles" not in settings.features, exit_msg)
335 _flush_elog_mod_echo()
337 if not vardbapi._pkgs_changed:
338 display_news_notification(root_config, myopts)
339 # If vdb state has not changed then there's nothing else to do.
342 vdb_path = os.path.join(target_root, portage.VDB_PATH)
343 portage.util.ensure_dirs(vdb_path)
345 if os.access(vdb_path, os.W_OK) and not "--pretend" in myopts:
346 vdb_lock = portage.locks.lockdir(vdb_path)
350 if "noinfo" not in settings.features:
351 chk_updated_info_files(target_root,
352 infodirs, info_mtimes, retval)
356 portage.locks.unlockdir(vdb_lock)
358 chk_updated_cfg_files(target_root, config_protect)
360 display_news_notification(root_config, myopts)
361 if retval in (None, os.EX_OK) or (not "--pretend" in myopts):
362 display_preserved_libs(vardbapi, myopts)
366 def multiple_actions(action1, action2):
367 sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n")
368 sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2))
371 def insert_optional_args(args):
373 Parse optional arguments and insert a value if one has
374 not been provided. This is done before feeding the args
375 to the optparse parser since that parser does not support
376 this feature natively.
379 class valid_integers(object):
380 def __contains__(self, s):
383 except (ValueError, OverflowError):
386 valid_integers = valid_integers()
391 '--complete-graph' : ('n',),
392 '--deep' : valid_integers,
393 '--depclean-lib-check' : ('n',),
394 '--deselect' : ('n',),
395 '--binpkg-respect-use' : ('n', 'y',),
396 '--fail-clean' : ('n',),
397 '--getbinpkg' : ('n',),
398 '--getbinpkgonly' : ('n',),
399 '--jobs' : valid_integers,
400 '--keep-going' : ('n',),
401 '--rebuilt-binaries' : ('n',),
402 '--root-deps' : ('rdeps',),
404 '--selective' : ('n',),
405 "--use-ebuild-visibility": ('n',),
407 '--usepkgonly' : ('n',),
411 'D' : valid_integers,
412 'j' : valid_integers,
415 # Don't make things like "-kn" expand to "-k n"
416 # since existence of -n makes it too ambiguous.
427 arg = arg_stack.pop()
429 default_arg_choices = default_arg_opts.get(arg)
430 if default_arg_choices is not None:
432 if arg_stack and arg_stack[-1] in default_arg_choices:
433 new_args.append(arg_stack.pop())
435 # insert default argument
436 new_args.append('True')
439 if arg[:1] != "-" or arg[:2] == "--":
444 for k, arg_choices in short_arg_opts.items():
450 for k, arg_choices in short_arg_opts_n.items():
461 if arg_stack and arg_stack[-1] in arg_choices:
462 new_args.append(arg_stack.pop())
464 # insert default argument
465 new_args.append('True')
468 # Insert an empty placeholder in order to
469 # satisfy the requirements of optparse.
471 new_args.append("-" + match)
475 if arg[1:2] == match:
476 if match not in short_arg_opts_n and arg[2:] in arg_choices:
482 saved_opts = arg[1:].replace(match, "")
485 if opt_arg is None and arg_stack and \
486 arg_stack[-1] in arg_choices:
487 opt_arg = arg_stack.pop()
490 new_args.append("True")
492 new_args.append(opt_arg)
494 if saved_opts is not None:
495 # Recycle these on arg_stack since they
496 # might contain another match.
497 arg_stack.append("-" + saved_opts)
501 def parse_opts(tmpcmdline, silent=False):
506 global options, shortmapping
508 actions = frozenset([
509 "clean", "config", "depclean", "help",
510 "info", "list-sets", "metadata",
511 "prune", "regen", "search",
512 "sync", "unmerge", "version",
515 longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"}
517 "--accept-properties": {
518 "help":"temporarily override ACCEPT_PROPERTIES",
524 "help" : "Specifies how many times to backtrack if dependency " + \
525 "calculation fails ",
531 "help":"specify the location for portage configuration files",
535 "help":"enable or disable color output",
540 "--complete-graph": {
541 "help" : "completely account for all known dependencies",
543 "choices" : ("True", "n")
550 "help" : "Specifies how deep to recurse into dependencies " + \
551 "of packages given as arguments. If no argument is given, " + \
552 "depth is unlimited. Default behavior is to skip " + \
553 "dependencies of installed packages.",
558 "--depclean-lib-check": {
559 "help" : "check for consumers of libraries before removing them",
561 "choices" : ("True", "n")
565 "help" : "remove atoms/sets from the world file",
567 "choices" : ("True", "n")
571 "help" :"A space separated list of package names or slot atoms. " + \
572 "Emerge won't install any ebuild or binary package that " + \
573 "matches any of the given package atoms.",
579 "help" : "clean temp files after build failure",
581 "choices" : ("True", "n")
588 "help" : "Specifies the number of packages to build " + \
595 "help" : "continue as much as possible after an error",
597 "choices" : ("True", "n")
602 "help" :"Specifies that no new builds should be started " + \
603 "if there are other builds running and the load average " + \
604 "is at least LOAD (a floating-point number).",
610 "help":"include unnecessary build time dependencies",
615 "help":"specify conditions to trigger package reinstallation",
617 "choices":["changed-use"]
620 "--binpkg-respect-use": {
621 "help" : "discard binary packages if their use flags \
622 don't match the current configuration",
624 "choices" : ("True", "y", "n")
629 "help" : "fetch binary packages",
631 "choices" : ("True", "n")
636 "help" : "fetch binary packages only",
638 "choices" : ("True", "n")
641 "--rebuilt-binaries": {
642 "help" : "replace installed packages with binary " + \
643 "packages that have been rebuilt",
645 "choices" : ("True", "n")
648 "--rebuilt-binaries-timestamp": {
649 "help" : "use only binaries that are newer than this " + \
650 "timestamp for --rebuilt-binaries",
655 "help" : "specify the target root filesystem for merging packages",
660 "help" : "modify interpretation of depedencies",
662 "choices" :("True", "rdeps")
666 "help" : "add specified packages to the world set " + \
667 "(inverse of --oneshot)",
669 "choices" : ("True", "n")
673 "help" : "similar to the --noreplace but does not take " + \
674 "precedence over options such as --newuse",
676 "choices" : ("True", "n")
679 "--use-ebuild-visibility": {
680 "help" : "use unbuilt ebuild metadata for visibility checks on built packages",
682 "choices" : ("True", "n")
687 "help" : "use binary packages",
689 "choices" : ("True", "n")
694 "help" : "use only binary packages",
696 "choices" : ("True", "n")
701 from optparse import OptionParser
702 parser = OptionParser()
703 if parser.has_option("--help"):
704 parser.remove_option("--help")
706 for action_opt in actions:
707 parser.add_option("--" + action_opt, action="store_true",
708 dest=action_opt.replace("-", "_"), default=False)
709 for myopt in options:
710 parser.add_option(myopt, action="store_true",
711 dest=myopt.lstrip("--").replace("-", "_"), default=False)
712 for shortopt, longopt in shortmapping.items():
713 parser.add_option("-" + shortopt, action="store_true",
714 dest=longopt.lstrip("--").replace("-", "_"), default=False)
715 for myalias, myopt in longopt_aliases.items():
716 parser.add_option(myalias, action="store_true",
717 dest=myopt.lstrip("--").replace("-", "_"), default=False)
719 for myopt, kwargs in argument_options.items():
720 shortopt = kwargs.pop("shortopt", None)
722 if shortopt is not None:
723 args.append(shortopt)
724 parser.add_option(dest=myopt.lstrip("--").replace("-", "_"),
727 tmpcmdline = insert_optional_args(tmpcmdline)
729 myoptions, myargs = parser.parse_args(args=tmpcmdline)
731 if myoptions.changed_use is not False:
732 myoptions.reinstall = "changed-use"
733 myoptions.changed_use = False
735 if myoptions.deselect == "True":
736 myoptions.deselect = True
738 if myoptions.binpkg_respect_use in ("y", "True",):
739 myoptions.binpkg_respect_use = True
741 myoptions.binpkg_respect_use = None
743 if myoptions.complete_graph in ("y", "True",):
744 myoptions.complete_graph = True
746 myoptions.complete_graph = None
748 if myoptions.depclean_lib_check in ("True",):
749 myoptions.depclean_lib_check = True
751 if myoptions.exclude:
754 for x in ' '.join(myoptions.exclude).split():
757 atom = portage.dep.Atom(x, allow_wildcard=True)
758 except portage.exception.InvalidAtom:
760 atom = portage.dep.Atom("*/"+x, allow_wildcard=True)
761 except portage.exception.InvalidAtom:
767 if atom.operator or atom.blocker or atom.use:
772 if bad_atoms and not silent:
773 parser.error("Invalid Atom(s) in --exclude parameter: '%s' (only package names and slot atoms (with widlcards) allowed)\n" % \
774 (",".join(bad_atoms),))
776 if myoptions.fail_clean == "True":
777 myoptions.fail_clean = True
779 if myoptions.getbinpkg in ("True",):
780 myoptions.getbinpkg = True
782 myoptions.getbinpkg = None
784 if myoptions.getbinpkgonly in ("True",):
785 myoptions.getbinpkgonly = True
787 myoptions.getbinpkgonly = None
789 if myoptions.keep_going in ("True",):
790 myoptions.keep_going = True
792 myoptions.keep_going = None
794 if myoptions.rebuilt_binaries in ("True",):
795 myoptions.rebuilt_binaries = True
797 if myoptions.root_deps == "True":
798 myoptions.root_deps = True
800 if myoptions.select == "True":
801 myoptions.select = True
802 myoptions.oneshot = False
803 elif myoptions.select == "n":
804 myoptions.oneshot = True
806 if myoptions.selective == "True":
807 myoptions.selective = True
809 if myoptions.backtrack is not None:
812 backtrack = int(myoptions.backtrack)
813 except (OverflowError, ValueError):
819 parser.error("Invalid --backtrack parameter: '%s'\n" % \
820 (myoptions.backtrack,))
822 myoptions.backtrack = backtrack
824 if myoptions.deep is not None:
826 if myoptions.deep == "True":
830 deep = int(myoptions.deep)
831 except (OverflowError, ValueError):
834 if deep is not True and deep < 0:
837 parser.error("Invalid --deep parameter: '%s'\n" % \
840 myoptions.deep = deep
844 if myoptions.jobs == "True":
848 jobs = int(myoptions.jobs)
852 if jobs is not True and \
856 parser.error("Invalid --jobs parameter: '%s'\n" % \
859 myoptions.jobs = jobs
861 if myoptions.load_average:
863 load_average = float(myoptions.load_average)
867 if load_average <= 0.0:
870 parser.error("Invalid --load-average parameter: '%s'\n" % \
871 (myoptions.load_average,))
873 myoptions.load_average = load_average
875 if myoptions.rebuilt_binaries_timestamp:
877 rebuilt_binaries_timestamp = int(myoptions.rebuilt_binaries_timestamp)
879 rebuilt_binaries_timestamp = -1
881 if rebuilt_binaries_timestamp < 0:
882 rebuilt_binaries_timestamp = 0
884 parser.error("Invalid --rebuilt-binaries-timestamp parameter: '%s'\n" % \
885 (myoptions.rebuilt_binaries_timestamp,))
887 myoptions.rebuilt_binaries_timestamp = rebuilt_binaries_timestamp
889 if myoptions.use_ebuild_visibility in ("True",):
890 myoptions.use_ebuild_visibility = True
892 myoptions.use_ebuild_visibility = None
894 if myoptions.usepkg in ("True",):
895 myoptions.usepkg = True
897 myoptions.usepkg = None
899 if myoptions.usepkgonly in ("True",):
900 myoptions.usepkgonly = True
902 myoptions.usepkgonly = None
904 for myopt in options:
905 v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"))
909 for myopt in argument_options:
910 v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None)
914 if myoptions.searchdesc:
915 myoptions.search = True
917 for action_opt in actions:
918 v = getattr(myoptions, action_opt.replace("-", "_"))
921 multiple_actions(myaction, action_opt)
923 myaction = action_opt
925 if myaction is None and myoptions.deselect is True:
926 myaction = 'deselect'
928 if myargs and sys.hexversion < 0x3000000 and \
929 not isinstance(myargs[0], unicode):
930 for i in range(len(myargs)):
931 myargs[i] = portage._unicode_decode(myargs[i])
935 return myaction, myopts, myfiles
937 def validate_ebuild_environment(trees):
939 settings = trees[myroot]["vartree"].settings
942 def apply_priorities(settings):
948 os.nice(int(settings.get("PORTAGE_NICENESS", "0")))
949 except (OSError, ValueError) as e:
950 out = portage.output.EOutput()
951 out.eerror("Failed to change nice value to '%s'" % \
952 settings["PORTAGE_NICENESS"])
953 out.eerror("%s\n" % str(e))
955 def ionice(settings):
957 ionice_cmd = settings.get("PORTAGE_IONICE_COMMAND")
959 ionice_cmd = portage.util.shlex_split(ionice_cmd)
963 from portage.util import varexpand
964 variables = {"PID" : str(os.getpid())}
965 cmd = [varexpand(x, mydict=variables) for x in ionice_cmd]
968 rval = portage.process.spawn(cmd, env=os.environ)
969 except portage.exception.CommandNotFound:
970 # The OS kernel probably doesn't support ionice,
971 # so return silently.
975 out = portage.output.EOutput()
976 out.eerror("PORTAGE_IONICE_COMMAND returned %d" % (rval,))
977 out.eerror("See the make.conf(5) man page for PORTAGE_IONICE_COMMAND usage instructions.")
979 def setconfig_fallback(root_config):
980 from portage.sets.base import DummyPackageSet
981 from portage.sets.files import WorldSelectedSet
982 from portage.sets.profiles import PackagesSystemSet
983 setconfig = root_config.setconfig
984 setconfig.psets['world'] = DummyPackageSet(atoms=['@selected', '@system'])
985 setconfig.psets['selected'] = WorldSelectedSet(root_config.root)
986 setconfig.psets['system'] = \
987 PackagesSystemSet(root_config.settings.profiles)
988 root_config.sets = setconfig.getSets()
990 def get_missing_sets(root_config):
991 # emerge requires existence of "world", "selected", and "system"
994 for s in ("selected", "system", "world",):
995 if s not in root_config.sets:
996 missing_sets.append(s)
1000 def missing_sets_warning(root_config, missing_sets):
1001 if len(missing_sets) > 2:
1002 missing_sets_str = ", ".join('"%s"' % s for s in missing_sets[:-1])
1003 missing_sets_str += ', and "%s"' % missing_sets[-1]
1004 elif len(missing_sets) == 2:
1005 missing_sets_str = '"%s" and "%s"' % tuple(missing_sets)
1007 missing_sets_str = '"%s"' % missing_sets[-1]
1008 msg = ["emerge: incomplete set configuration, " + \
1009 "missing set(s): %s" % missing_sets_str]
1010 if root_config.sets:
1011 msg.append(" sets defined: %s" % ", ".join(root_config.sets))
1012 msg.append(" This usually means that '%s'" % \
1013 (os.path.join(portage.const.GLOBAL_CONFIG_PATH, "sets/portage.conf"),))
1014 msg.append(" is missing or corrupt.")
1015 msg.append(" Falling back to default world and system set configuration!!!")
1017 writemsg_level(line + "\n", level=logging.ERROR, noiselevel=-1)
1019 def ensure_required_sets(trees):
1020 warning_shown = False
1021 for root_trees in trees.values():
1022 missing_sets = get_missing_sets(root_trees["root_config"])
1023 if missing_sets and not warning_shown:
1024 warning_shown = True
1025 missing_sets_warning(root_trees["root_config"], missing_sets)
1027 setconfig_fallback(root_trees["root_config"])
1029 def expand_set_arguments(myfiles, myaction, root_config):
1031 setconfig = root_config.setconfig
1033 sets = setconfig.getSets()
1035 # In order to know exactly which atoms/sets should be added to the
1036 # world file, the depgraph performs set expansion later. It will get
1037 # confused about where the atoms came from if it's not allowed to
1038 # expand them itself.
1039 do_not_expand = (None, )
1042 if a in ("system", "world"):
1043 newargs.append(SETPREFIX+a)
1050 # separators for set arguments
1054 for i in range(0, len(myfiles)):
1055 if myfiles[i].startswith(SETPREFIX):
1058 x = myfiles[i][len(SETPREFIX):]
1061 start = x.find(ARG_START)
1062 end = x.find(ARG_END)
1063 if start > 0 and start < end:
1064 namepart = x[:start]
1065 argpart = x[start+1:end]
1067 # TODO: implement proper quoting
1068 args = argpart.split(",")
1072 k, v = a.split("=", 1)
1076 setconfig.update(namepart, options)
1077 newset += (x[:start-len(namepart)]+namepart)
1078 x = x[end+len(ARG_END):]
1082 myfiles[i] = SETPREFIX+newset
1084 sets = setconfig.getSets()
1086 # display errors that occured while loading the SetConfig instance
1087 for e in setconfig.errors:
1088 print(colorize("BAD", "Error during set creation: %s" % e))
1090 unmerge_actions = ("unmerge", "prune", "clean", "depclean")
1093 if a.startswith(SETPREFIX):
1094 s = a[len(SETPREFIX):]
1096 display_missing_pkg_set(root_config, s)
1098 setconfig.active.append(s)
1100 set_atoms = setconfig.getSetAtoms(s)
1101 except portage.exception.PackageSetNotFound as e:
1102 writemsg_level(("emerge: the given set '%s' " + \
1103 "contains a non-existent set named '%s'.\n") % \
1104 (s, e), level=logging.ERROR, noiselevel=-1)
1106 if myaction in unmerge_actions and \
1107 not sets[s].supportsOperation("unmerge"):
1108 sys.stderr.write("emerge: the given set '%s' does " % s + \
1109 "not support unmerge operations\n")
1112 print("emerge: '%s' is an empty set" % s)
1113 elif myaction not in do_not_expand:
1114 newargs.extend(set_atoms)
1116 newargs.append(SETPREFIX+s)
1117 for e in sets[s].errors:
1121 return (newargs, retval)
1123 def repo_name_check(trees):
1124 missing_repo_names = set()
1125 for root, root_trees in trees.items():
1126 if "porttree" in root_trees:
1127 portdb = root_trees["porttree"].dbapi
1128 missing_repo_names.update(portdb.porttrees)
1129 repos = portdb.getRepositories()
1131 missing_repo_names.discard(portdb.getRepositoryPath(r))
1132 if portdb.porttree_root in missing_repo_names and \
1133 not os.path.exists(os.path.join(
1134 portdb.porttree_root, "profiles")):
1135 # This is normal if $PORTDIR happens to be empty,
1136 # so don't warn about it.
1137 missing_repo_names.remove(portdb.porttree_root)
1139 if missing_repo_names:
1141 msg.append("WARNING: One or more repositories " + \
1142 "have missing repo_name entries:")
1144 for p in missing_repo_names:
1145 msg.append("\t%s/profiles/repo_name" % (p,))
1147 msg.extend(textwrap.wrap("NOTE: Each repo_name entry " + \
1148 "should be a plain text file containing a unique " + \
1149 "name for the repository on the first line.", 70))
1150 writemsg_level("".join("%s\n" % l for l in msg),
1151 level=logging.WARNING, noiselevel=-1)
1153 return bool(missing_repo_names)
1155 def repo_name_duplicate_check(trees):
1157 for root, root_trees in trees.items():
1158 if 'porttree' in root_trees:
1159 portdb = root_trees['porttree'].dbapi
1160 if portdb.settings.get('PORTAGE_REPO_DUPLICATE_WARN') != '0':
1161 for repo_name, paths in portdb._ignored_repos:
1162 k = (root, repo_name, portdb.getRepositoryPath(repo_name))
1163 ignored_repos.setdefault(k, []).extend(paths)
1167 msg.append('WARNING: One or more repositories ' + \
1168 'have been ignored due to duplicate')
1169 msg.append(' profiles/repo_name entries:')
1171 for k in sorted(ignored_repos):
1172 msg.append(' %s overrides' % (k,))
1173 for path in ignored_repos[k]:
1174 msg.append(' %s' % (path,))
1176 msg.extend(' ' + x for x in textwrap.wrap(
1177 "All profiles/repo_name entries must be unique in order " + \
1178 "to avoid having duplicates ignored. " + \
1179 "Set PORTAGE_REPO_DUPLICATE_WARN=\"0\" in " + \
1180 "/etc/make.conf if you would like to disable this warning."))
1181 writemsg_level(''.join('%s\n' % l for l in msg),
1182 level=logging.WARNING, noiselevel=-1)
1184 return bool(ignored_repos)
1186 def config_protect_check(trees):
1187 for root, root_trees in trees.items():
1188 if not root_trees["root_config"].settings.get("CONFIG_PROTECT"):
1189 msg = "!!! CONFIG_PROTECT is empty"
1191 msg += " for '%s'" % root
1193 writemsg_level(msg, level=logging.WARN, noiselevel=-1)
1195 def profile_check(trees, myaction):
1196 if myaction in ("help", "info", "sync", "version"):
1198 for root, root_trees in trees.items():
1199 if root_trees["root_config"].settings.profiles:
1201 # generate some profile related warning messages
1202 validate_ebuild_environment(trees)
1203 msg = "If you have just changed your profile configuration, you " + \
1204 "should revert back to the previous configuration. Due to " + \
1205 "your current profile being invalid, allowed actions are " + \
1206 "limited to --help, --info, --sync, and --version."
1207 writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)),
1208 level=logging.ERROR, noiselevel=-1)
1213 procfs_path = '/proc'
1214 if platform.system() not in ("Linux",) or \
1215 os.path.ismount(procfs_path):
1217 msg = "It seems that %s is not mounted. You have been warned." % procfs_path
1218 writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)),
1219 level=logging.ERROR, noiselevel=-1)
1223 global portage # NFC why this is necessary now - genone
1224 portage._disable_legacy_globals()
1225 # Disable color until we're sure that it should be enabled (after
1226 # EMERGE_DEFAULT_OPTS has been parsed).
1227 portage.output.havecolor = 0
1228 # This first pass is just for options that need to be known as early as
1229 # possible, such as --config-root. They will be parsed again later,
1230 # together with EMERGE_DEFAULT_OPTS (which may vary depending on the
1231 # the value of --config-root).
1232 myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True)
1233 if "--debug" in myopts:
1234 os.environ["PORTAGE_DEBUG"] = "1"
1235 if "--config-root" in myopts:
1236 os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"]
1237 if "--root" in myopts:
1238 os.environ["ROOT"] = myopts["--root"]
1239 if "--accept-properties" in myopts:
1240 os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"]
1242 # Portage needs to ensure a sane umask for the files it creates.
1244 settings, trees, mtimedb = load_emerge_config()
1245 portdb = trees[settings["ROOT"]]["porttree"].dbapi
1246 rval = profile_check(trees, myaction)
1247 if rval != os.EX_OK:
1250 if myaction not in ('help', 'info', 'version') and \
1251 _global_updates(trees, mtimedb["updates"]):
1253 # Reload the whole config from scratch.
1254 settings, trees, mtimedb = load_emerge_config(trees=trees)
1255 portdb = trees[settings["ROOT"]]["porttree"].dbapi
1257 xterm_titles = "notitles" not in settings.features
1259 xtermTitle("emerge")
1262 if "--ignore-default-opts" not in myopts:
1263 tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split())
1264 tmpcmdline.extend(sys.argv[1:])
1265 myaction, myopts, myfiles = parse_opts(tmpcmdline)
1267 if "--digest" in myopts:
1268 os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest"
1269 # Reload the whole config from scratch so that the portdbapi internal
1270 # config is updated with new FEATURES.
1271 settings, trees, mtimedb = load_emerge_config(trees=trees)
1272 portdb = trees[settings["ROOT"]]["porttree"].dbapi
1274 adjust_configs(myopts, trees)
1275 apply_priorities(settings)
1277 if myaction == 'version':
1278 writemsg_stdout(getportageversion(
1279 settings["PORTDIR"], settings["ROOT"],
1280 settings.profile_path, settings["CHOST"],
1281 trees[settings["ROOT"]]["vartree"].dbapi) + '\n', noiselevel=-1)
1283 elif myaction == 'help':
1284 _emerge.help.help(myopts, portage.output.havecolor)
1287 spinner = stdout_spinner()
1288 if "candy" in settings.features:
1289 spinner.update = spinner.update_scroll
1291 if "--quiet" not in myopts:
1292 portage.deprecated_profile_check(settings=settings)
1293 repo_name_check(trees)
1294 repo_name_duplicate_check(trees)
1295 config_protect_check(trees)
1298 if "getbinpkg" in settings.features:
1299 myopts["--getbinpkg"] = True
1301 if "--getbinpkgonly" in myopts:
1302 myopts["--getbinpkg"] = True
1304 if "--getbinpkgonly" in myopts:
1305 myopts["--usepkgonly"] = True
1307 if "--getbinpkg" in myopts:
1308 myopts["--usepkg"] = True
1310 if "--usepkgonly" in myopts:
1311 myopts["--usepkg"] = True
1313 if "buildpkg" in settings.features or "--buildpkgonly" in myopts:
1314 myopts["--buildpkg"] = True
1316 if "--buildpkgonly" in myopts:
1317 # --buildpkgonly will not merge anything, so
1318 # it cancels all binary package options.
1319 for opt in ("--getbinpkg", "--getbinpkgonly",
1320 "--usepkg", "--usepkgonly"):
1321 myopts.pop(opt, None)
1323 for mytrees in trees.values():
1324 mydb = mytrees["porttree"].dbapi
1325 # Freeze the portdbapi for performance (memoize all xmatch results).
1328 if "--usepkg" in myopts:
1329 # Populate the bintree with current --getbinpkg setting.
1330 # This needs to happen before expand_set_arguments(), in case
1331 # any sets use the bintree.
1332 mytrees["bintree"].populate(
1333 getbinpkgs="--getbinpkg" in myopts)
1337 if "moo" in myfiles:
1340 Larry loves Gentoo (""" + platform.system() + """)
1342 _______________________
1343 < Have you mooed today? >
1344 -----------------------
1354 ext = os.path.splitext(x)[1]
1355 if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
1356 print(colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n"))
1359 root_config = trees[settings["ROOT"]]["root_config"]
1360 if myaction == "list-sets":
1361 writemsg_stdout("".join("%s\n" % s for s in sorted(root_config.sets)))
1364 ensure_required_sets(trees)
1366 # only expand sets for actions taking package arguments
1367 oldargs = myfiles[:]
1368 if myaction in ("clean", "config", "depclean", "info", "prune", "unmerge", None):
1369 myfiles, retval = expand_set_arguments(myfiles, myaction, root_config)
1370 if retval != os.EX_OK:
1373 # Need to handle empty sets specially, otherwise emerge will react
1374 # with the help message for empty argument lists
1375 if oldargs and not myfiles:
1376 print("emerge: no targets left after set expansion")
1379 if ("--tree" in myopts) and ("--columns" in myopts):
1380 print("emerge: can't specify both of \"--tree\" and \"--columns\".")
1383 if '--emptytree' in myopts and '--noreplace' in myopts:
1384 writemsg_level("emerge: can't specify both of " + \
1385 "\"--emptytree\" and \"--noreplace\".\n",
1386 level=logging.ERROR, noiselevel=-1)
1389 if ("--quiet" in myopts):
1390 spinner.update = spinner.update_quiet
1391 portage.util.noiselimit = -1
1393 if "--fetch-all-uri" in myopts:
1394 myopts["--fetchonly"] = True
1396 if "--skipfirst" in myopts and "--resume" not in myopts:
1397 myopts["--resume"] = True
1399 # Allow -p to remove --ask
1400 if "--pretend" in myopts:
1401 myopts.pop("--ask", None)
1403 # forbid --ask when not in a terminal
1404 # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
1405 if ("--ask" in myopts) and (not sys.stdin.isatty()):
1406 portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n",
1410 if settings.get("PORTAGE_DEBUG", "") == "1":
1411 spinner.update = spinner.update_quiet
1413 if "python-trace" in settings.features:
1414 import portage.debug
1415 portage.debug.set_trace(True)
1417 if not ("--quiet" in myopts):
1418 if '--nospinner' in myopts or \
1419 settings.get('TERM') == 'dumb' or \
1420 not sys.stdout.isatty():
1421 spinner.update = spinner.update_basic
1423 if "--debug" in myopts:
1424 print("myaction", myaction)
1425 print("myopts", myopts)
1427 if not myaction and not myfiles and "--resume" not in myopts:
1428 _emerge.help.help(myopts, portage.output.havecolor)
1431 pretend = "--pretend" in myopts
1432 fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts
1433 buildpkgonly = "--buildpkgonly" in myopts
1435 # check if root user is the current user for the actions where emerge needs this
1436 if portage.secpass < 2:
1437 # We've already allowed "--version" and "--help" above.
1438 if "--pretend" not in myopts and myaction not in ("search","info"):
1439 need_superuser = myaction in ('clean', 'depclean', 'deselect',
1440 'prune', 'unmerge') or not \
1442 (buildpkgonly and secpass >= 1) or \
1443 myaction in ("metadata", "regen") or \
1444 (myaction == "sync" and os.access(settings["PORTDIR"], os.W_OK)))
1445 if portage.secpass < 1 or \
1448 access_desc = "superuser"
1450 access_desc = "portage group"
1451 # Always show portage_group_warning() when only portage group
1452 # access is required but the user is not in the portage group.
1453 from portage.data import portage_group_warning
1454 if "--ask" in myopts:
1455 myopts["--pretend"] = True
1457 print(("%s access is required... " + \
1458 "adding --pretend to options\n") % access_desc)
1459 if portage.secpass < 1 and not need_superuser:
1460 portage_group_warning()
1462 sys.stderr.write(("emerge: %s access is required\n") \
1464 if portage.secpass < 1 and not need_superuser:
1465 portage_group_warning()
1468 disable_emergelog = False
1469 for x in ("--pretend", "--fetchonly", "--fetch-all-uri"):
1471 disable_emergelog = True
1473 if myaction in ("search", "info"):
1474 disable_emergelog = True
1475 if disable_emergelog:
1476 """ Disable emergelog for everything except build or unmerge
1477 operations. This helps minimize parallel emerge.log entries that can
1478 confuse log parsers. We especially want it disabled during
1479 parallel-fetch, which uses --resume --fetchonly."""
1480 _emerge.emergelog._disable = True
1483 if 'EMERGE_LOG_DIR' in settings:
1485 # At least the parent needs to exist for the lock file.
1486 portage.util.ensure_dirs(settings['EMERGE_LOG_DIR'])
1487 except portage.exception.PortageException as e:
1488 writemsg_level("!!! Error creating directory for " + \
1489 "EMERGE_LOG_DIR='%s':\n!!! %s\n" % \
1490 (settings['EMERGE_LOG_DIR'], e),
1491 noiselevel=-1, level=logging.ERROR)
1493 global _emerge_log_dir
1494 _emerge_log_dir = settings['EMERGE_LOG_DIR']
1496 if not "--pretend" in myopts:
1497 emergelog(xterm_titles, "Started emerge on: "+\
1499 time.strftime("%b %d, %Y %H:%M:%S", time.localtime()),
1500 encoding=_encodings['content'], errors='replace'))
1503 myelogstr=" ".join(myopts)
1505 myelogstr+=" "+myaction
1507 myelogstr += " " + " ".join(oldargs)
1508 emergelog(xterm_titles, " *** emerge " + myelogstr)
1511 def emergeexitsig(signum, frame):
1512 signal.signal(signal.SIGINT, signal.SIG_IGN)
1513 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1514 portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
1515 sys.exit(100+signum)
1516 signal.signal(signal.SIGINT, emergeexitsig)
1517 signal.signal(signal.SIGTERM, emergeexitsig)
1520 """This gets out final log message in before we quit."""
1521 if "--pretend" not in myopts:
1522 emergelog(xterm_titles, " *** terminating.")
1525 portage.atexit_register(emergeexit)
1527 if myaction in ("config", "metadata", "regen", "sync"):
1528 if "--pretend" in myopts:
1529 sys.stderr.write(("emerge: The '%s' action does " + \
1530 "not support '--pretend'.\n") % myaction)
1533 if "sync" == myaction:
1534 return action_sync(settings, trees, mtimedb, myopts, myaction)
1535 elif "metadata" == myaction:
1536 action_metadata(settings, portdb, myopts)
1537 elif myaction=="regen":
1538 validate_ebuild_environment(trees)
1539 return action_regen(settings, portdb, myopts.get("--jobs"),
1540 myopts.get("--load-average"))
1542 elif "config"==myaction:
1543 validate_ebuild_environment(trees)
1544 action_config(settings, trees, myopts, myfiles)
1547 elif "search"==myaction:
1548 validate_ebuild_environment(trees)
1549 action_search(trees[settings["ROOT"]]["root_config"],
1550 myopts, myfiles, spinner)
1552 elif myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge'):
1553 validate_ebuild_environment(trees)
1554 rval = action_uninstall(settings, trees, mtimedb["ldpath"],
1555 myopts, myaction, myfiles, spinner)
1556 if not (myaction == 'deselect' or buildpkgonly or fetchonly or pretend):
1557 post_emerge(root_config, myopts, mtimedb, rval)
1560 elif myaction == 'info':
1562 # Ensure atoms are valid before calling unmerge().
1563 vardb = trees[settings["ROOT"]]["vartree"].dbapi
1564 portdb = trees[settings["ROOT"]]["porttree"].dbapi
1565 bindb = trees[settings["ROOT"]]["bintree"].dbapi
1568 if is_valid_package_atom(x):
1570 #look at the installed files first, if there is no match
1571 #look at the ebuilds, since EAPI 4 allows running pkg_info
1572 #on non-installed packages
1573 valid_atom = dep_expand(x, mydb=vardb, settings=settings)
1574 if valid_atom.cp.split("/")[0] == "null":
1575 valid_atom = dep_expand(x, mydb=portdb, settings=settings)
1576 if valid_atom.cp.split("/")[0] == "null" and "--usepkg" in myopts:
1577 valid_atom = dep_expand(x, mydb=bindb, settings=settings)
1578 valid_atoms.append(valid_atom)
1579 except portage.exception.AmbiguousPackageName as e:
1580 msg = "The short ebuild name \"" + x + \
1581 "\" is ambiguous. Please specify " + \
1582 "one of the following " + \
1583 "fully-qualified ebuild names instead:"
1584 for line in textwrap.wrap(msg, 70):
1585 writemsg_level("!!! %s\n" % (line,),
1586 level=logging.ERROR, noiselevel=-1)
1588 writemsg_level(" %s\n" % colorize("INFORM", i),
1589 level=logging.ERROR, noiselevel=-1)
1590 writemsg_level("\n", level=logging.ERROR, noiselevel=-1)
1594 msg.append("'%s' is not a valid package atom." % (x,))
1595 msg.append("Please check ebuild(5) for full details.")
1596 writemsg_level("".join("!!! %s\n" % line for line in msg),
1597 level=logging.ERROR, noiselevel=-1)
1600 return action_info(settings, trees, myopts, valid_atoms)
1602 # "update", "system", or just process files:
1604 validate_ebuild_environment(trees)
1607 if x.startswith(SETPREFIX) or \
1608 is_valid_package_atom(x):
1618 msg.append("'%s' is not a valid package atom." % (x,))
1619 msg.append("Please check ebuild(5) for full details.")
1620 writemsg_level("".join("!!! %s\n" % line for line in msg),
1621 level=logging.ERROR, noiselevel=-1)
1624 if "--pretend" not in myopts:
1625 display_news_notification(root_config, myopts)
1626 retval = action_build(settings, trees, mtimedb,
1627 myopts, myaction, myfiles, spinner)
1628 root_config = trees[settings["ROOT"]]["root_config"]
1629 post_emerge(root_config, myopts, mtimedb, retval)