diff options
Diffstat (limited to 'portage_with_autodep/pym/_emerge/actions.py')
-rw-r--r-- | portage_with_autodep/pym/_emerge/actions.py | 500 |
1 files changed, 234 insertions, 266 deletions
diff --git a/portage_with_autodep/pym/_emerge/actions.py b/portage_with_autodep/pym/_emerge/actions.py index 2166963..eaf5a15 100644 --- a/portage_with_autodep/pym/_emerge/actions.py +++ b/portage_with_autodep/pym/_emerge/actions.py @@ -1,18 +1,19 @@ -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import errno import logging +import operator import platform import pwd import random import re -import shutil import signal import socket import stat +import subprocess import sys import tempfile import textwrap @@ -20,20 +21,27 @@ import time from itertools import chain import portage +portage.proxy.lazyimport.lazyimport(globals(), + 'portage.news:count_unread_news,display_news_notifications', +) + +from portage.localization import _ from portage import os -from portage import subprocess_getstatusoutput -from portage import _unicode_decode +from portage import shutil +from portage import eapi_is_supported, _unicode_decode from portage.cache.cache_errors import CacheError -from portage.const import GLOBAL_CONFIG_PATH, NEWS_LIB_PATH +from portage.const import GLOBAL_CONFIG_PATH from portage.const import _ENABLE_DYN_LINK_MAP, _ENABLE_SET_CONFIG from portage.dbapi.dep_expand import dep_expand from portage.dbapi._expand_new_virt import expand_new_virt from portage.dep import Atom, extended_cp_match +from portage.eclass_cache import hashed_path from portage.exception import InvalidAtom from portage.output import blue, bold, colorize, create_color_func, darkgreen, \ red, yellow good = create_color_func("GOOD") bad = create_color_func("BAD") +warn = create_color_func("WARN") 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 @@ -180,8 +188,7 @@ def action_build(settings, trees, mtimedb, " entire repository or category at once." prefix = bad(" * ") writemsg(prefix + "\n") - from textwrap import wrap - for line in wrap(msg, 72): + for line in textwrap.wrap(msg, 72): writemsg("%s%s\n" % (prefix, line)) writemsg(prefix + "\n") @@ -209,7 +216,6 @@ def action_build(settings, trees, mtimedb, if isinstance(e, depgraph.UnsatisfiedResumeDep): mydepgraph = e.depgraph - from textwrap import wrap from portage.output import EOutput out = EOutput() @@ -248,7 +254,7 @@ def action_build(settings, trees, mtimedb, "to skip the first package in the list and " + \ "any other packages that may be " + \ "masked or have missing dependencies." - for line in wrap(msg, 72): + for line in textwrap.wrap(msg, 72): out.eerror(line) elif isinstance(e, portage.exception.PackageNotFound): out.eerror("An expected package is " + \ @@ -258,7 +264,7 @@ def action_build(settings, trees, mtimedb, "packages that are no longer " + \ "available. Please restart/continue " + \ "the operation manually." - for line in wrap(msg, 72): + for line in textwrap.wrap(msg, 72): out.eerror(line) if success: @@ -291,7 +297,7 @@ def action_build(settings, trees, mtimedb, success, mydepgraph, favorites = backtrack_depgraph( settings, trees, myopts, myparams, myaction, myfiles, spinner) except portage.exception.PackageSetNotFound as e: - root_config = trees[settings["ROOT"]]["root_config"] + root_config = trees[settings['EROOT']]['root_config'] display_missing_pkg_set(root_config, e.value) return 1 @@ -329,7 +335,7 @@ def action_build(settings, trees, mtimedb, mergecount += 1 if mergecount==0: - sets = trees[settings["ROOT"]]["root_config"].sets + sets = trees[settings['EROOT']]['root_config'].sets world_candidates = None if "selective" in myparams and \ not oneshot and favorites: @@ -362,7 +368,7 @@ def action_build(settings, trees, mtimedb, print() print("Quitting.") print() - return os.EX_OK + return 128 + signal.SIGINT # Don't ask again (e.g. when auto-cleaning packages after merge) myopts.pop("--ask", None) @@ -439,7 +445,7 @@ def action_build(settings, trees, mtimedb, if retval == os.EX_OK and not (buildpkgonly or fetchonly or pretend): if "yes" == settings.get("AUTOCLEAN"): portage.writemsg_stdout(">>> Auto-cleaning packages...\n") - unmerge(trees[settings["ROOT"]]["root_config"], + unmerge(trees[settings['EROOT']]['root_config'], myopts, "clean", [], ldpath_mtimes, autoclean=1) else: @@ -454,7 +460,7 @@ def action_config(settings, trees, myopts, myfiles): if len(myfiles) != 1: print(red("!!! config can only take a single package atom at this time\n")) sys.exit(1) - if not is_valid_package_atom(myfiles[0]): + if not is_valid_package_atom(myfiles[0], allow_repo=True): portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0], noiselevel=-1) portage.writemsg("!!! Please check ebuild(5) for full details.\n") @@ -462,7 +468,7 @@ def action_config(settings, trees, myopts, myfiles): sys.exit(1) print() try: - pkgs = trees[settings["ROOT"]]["vartree"].dbapi.match(myfiles[0]) + pkgs = trees[settings['EROOT']]['vartree'].dbapi.match(myfiles[0]) except portage.exception.AmbiguousPackageName as e: # Multiple matches thrown from cpv_expand pkgs = e.args[0] @@ -482,7 +488,7 @@ def action_config(settings, trees, myopts, myfiles): options.append("X") idx = userquery("Selection?", enter_invalid, responses=options) if idx == "X": - sys.exit(0) + sys.exit(128 + signal.SIGINT) pkg = pkgs[int(idx)-1] else: print("The following packages available:") @@ -496,21 +502,20 @@ def action_config(settings, trees, myopts, myfiles): print() if "--ask" in myopts: if userquery("Ready to configure %s?" % pkg, enter_invalid) == "No": - sys.exit(0) + sys.exit(128 + signal.SIGINT) else: print("Configuring pkg...") print() - ebuildpath = trees[settings["ROOT"]]["vartree"].dbapi.findname(pkg) + ebuildpath = trees[settings['EROOT']]['vartree'].dbapi.findname(pkg) mysettings = portage.config(clone=settings) - vardb = trees[mysettings["ROOT"]]["vartree"].dbapi + vardb = trees[mysettings['EROOT']]['vartree'].dbapi debug = mysettings.get("PORTAGE_DEBUG") == "1" - retval = portage.doebuild(ebuildpath, "config", mysettings["ROOT"], - mysettings, + retval = portage.doebuild(ebuildpath, "config", settings=mysettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1), cleanup=True, - mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree") + mydbapi = trees[settings['EROOT']]['vartree'].dbapi, tree="vartree") if retval == os.EX_OK: - portage.doebuild(ebuildpath, "clean", mysettings["ROOT"], - mysettings, debug=debug, mydbapi=vardb, tree="vartree") + portage.doebuild(ebuildpath, "clean", settings=mysettings, + debug=debug, mydbapi=vardb, tree="vartree") print() def action_depclean(settings, trees, ldpath_mtimes, @@ -550,7 +555,7 @@ def action_depclean(settings, trees, ldpath_mtimes, for x in msg: portage.writemsg_stdout(colorize("WARN", " * ") + x) - root_config = trees[settings['ROOT']]['root_config'] + root_config = trees[settings['EROOT']]['root_config'] vardb = root_config.trees['vartree'].dbapi args_set = InternalPackageSet(allow_repo=True) @@ -582,15 +587,15 @@ def action_depclean(settings, trees, ldpath_mtimes, return rval if cleanlist: - unmerge(root_config, myopts, "unmerge", + rval = unmerge(root_config, myopts, "unmerge", cleanlist, ldpath_mtimes, ordered=ordered, scheduler=scheduler) if action == "prune": - return + return rval if not cleanlist and "--quiet" in myopts: - return + return rval print("Packages installed: " + str(len(vardb.cpv_all()))) print("Packages in world: " + \ @@ -603,14 +608,17 @@ def action_depclean(settings, trees, ldpath_mtimes, else: print("Number removed: "+str(len(cleanlist))) + return rval + def calc_depclean(settings, trees, ldpath_mtimes, myopts, action, args_set, spinner): allow_missing_deps = bool(args_set) debug = '--debug' in myopts xterm_titles = "notitles" not in settings.features - myroot = settings["ROOT"] - root_config = trees[myroot]["root_config"] + root_len = len(settings["ROOT"]) + eroot = settings['EROOT'] + root_config = trees[eroot]["root_config"] psets = root_config.setconfig.psets deselect = myopts.get('--deselect') != 'n' required_sets = {} @@ -649,8 +657,8 @@ def calc_depclean(settings, trees, ldpath_mtimes, resolver_params = create_depgraph_params(myopts, "remove") resolver = depgraph(settings, trees, myopts, resolver_params, spinner) resolver._load_vdb() - vardb = resolver._frozen_config.trees[myroot]["vartree"].dbapi - real_vardb = trees[myroot]["vartree"].dbapi + vardb = resolver._frozen_config.trees[eroot]["vartree"].dbapi + real_vardb = trees[eroot]["vartree"].dbapi if action == "depclean": @@ -705,7 +713,8 @@ def calc_depclean(settings, trees, ldpath_mtimes, # that are also matched by argument atoms, but do not remove # them if they match the highest installed version. for pkg in vardb: - spinner.update() + if spinner is not None: + spinner.update() pkgs_for_cp = vardb.match_pkgs(pkg.cp) if not pkgs_for_cp or pkg not in pkgs_for_cp: raise AssertionError("package expected in matches: " + \ @@ -751,7 +760,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, del e required_sets['__excluded__'].add("=" + pkg.cpv) - success = resolver._complete_graph(required_sets={myroot:required_sets}) + success = resolver._complete_graph(required_sets={eroot:required_sets}) writemsg_level("\b\b... done!\n") resolver.display_problems() @@ -937,7 +946,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, consumers = {} for lib in pkg_dblink.getcontents(): - lib = lib[len(myroot):] + lib = lib[root_len:] lib_key = linkmap._obj_key(lib) lib_consumers = consumer_cache.get(lib_key) if lib_consumers is None: @@ -1053,9 +1062,8 @@ def calc_depclean(settings, trees, ldpath_mtimes, "the packages that pulled them in." prefix = bad(" * ") - from textwrap import wrap writemsg_level("".join(prefix + "%s\n" % line for \ - line in wrap(msg, 70)), level=logging.WARNING, noiselevel=-1) + line in textwrap.wrap(msg, 70)), level=logging.WARNING, noiselevel=-1) msg = [] for pkg in sorted(consumer_map, key=cmp_sort_key(cmp_pkg_cpv)): @@ -1095,7 +1103,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, writemsg_level("\nCalculating dependencies ") success = resolver._complete_graph( - required_sets={myroot:required_sets}) + required_sets={eroot:required_sets}) writemsg_level("\b\b... done!\n") resolver.display_problems() if not success: @@ -1137,7 +1145,6 @@ def calc_depclean(settings, trees, ldpath_mtimes, for node in clean_set: graph.add(node, None) - mydeps = [] for dep_type in dep_keys: depstr = node.metadata[dep_type] if not depstr: @@ -1153,7 +1160,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, % (priority,), noiselevel=-1, level=logging.DEBUG) try: - atoms = resolver._select_atoms(myroot, depstr, + atoms = resolver._select_atoms(eroot, depstr, myuse=node.use.enabled, parent=node, priority=priority)[node] except portage.exception.InvalidDependString: @@ -1226,7 +1233,7 @@ def calc_depclean(settings, trees, ldpath_mtimes, def action_deselect(settings, trees, opts, atoms): enter_invalid = '--ask-enter-invalid' in opts - root_config = trees[settings['ROOT']]['root_config'] + root_config = trees[settings['EROOT']]['root_config'] world_set = root_config.sets['selected'] if not hasattr(world_set, 'update'): writemsg_level("World @selected set does not appear to be mutable.\n", @@ -1291,7 +1298,7 @@ def action_deselect(settings, trees, opts, atoms): prompt = "Would you like to remove these " + \ "packages from your world favorites?" if userquery(prompt, enter_invalid) == 'No': - return os.EX_OK + return 128 + signal.SIGINT remaining = set(world_set) remaining.difference_update(discard_atoms) @@ -1325,11 +1332,12 @@ def action_info(settings, trees, myopts, myfiles): output_buffer = [] append = output_buffer.append - root_config = trees[settings['ROOT']]['root_config'] + root_config = trees[settings['EROOT']]['root_config'] + running_eroot = trees._running_eroot - append(getportageversion(settings["PORTDIR"], settings["ROOT"], + append(getportageversion(settings["PORTDIR"], None, settings.profile_path, settings["CHOST"], - trees[settings["ROOT"]]["vartree"].dbapi)) + trees[settings['EROOT']]["vartree"].dbapi)) header_width = 65 header_title = "System Settings" @@ -1347,7 +1355,14 @@ def action_info(settings, trees, myopts, myfiles): lastSync = "Unknown" append("Timestamp of tree: %s" % (lastSync,)) - output=subprocess_getstatusoutput("distcc --version") + try: + proc = subprocess.Popen(["distcc", "--version"], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError: + output = (1, None) + else: + output = _unicode_decode(proc.communicate()[0]).rstrip("\n") + output = (proc.wait(), output) if output[0] == os.EX_OK: distcc_str = output[1].split("\n", 1)[0] if "distcc" in settings.features: @@ -1356,7 +1371,14 @@ def action_info(settings, trees, myopts, myfiles): distcc_str += " [disabled]" append(distcc_str) - output=subprocess_getstatusoutput("ccache -V") + try: + proc = subprocess.Popen(["ccache", "-V"], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError: + output = (1, None) + else: + output = _unicode_decode(proc.communicate()[0]).rstrip("\n") + output = (proc.wait(), output) if output[0] == os.EX_OK: ccache_str = output[1].split("\n", 1)[0] if "ccache" in settings.features: @@ -1369,7 +1391,7 @@ def action_info(settings, trees, myopts, myfiles): "sys-devel/binutils", "sys-devel/libtool", "dev-lang/python"] myvars += portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_pkgs") atoms = [] - vardb = trees["/"]["vartree"].dbapi + vardb = trees[running_eroot]['vartree'].dbapi for x in myvars: try: x = Atom(x) @@ -1382,7 +1404,7 @@ def action_info(settings, trees, myopts, myfiles): myvars = sorted(set(atoms)) - portdb = trees["/"]["porttree"].dbapi + portdb = trees[running_eroot]['porttree'].dbapi main_repo = portdb.getRepositoryName(portdb.porttree_root) cp_map = {} cp_max_len = 0 @@ -1425,8 +1447,6 @@ def action_info(settings, trees, myopts, myfiles): append("%s %s" % \ ((cp + ":").ljust(cp_max_len + 1), versions)) - libtool_vers = ",".join(trees["/"]["vartree"].dbapi.match("sys-devel/libtool")) - repos = portdb.settings.repositories if "--verbose" in myopts: append("Repositories:\n") @@ -1463,9 +1483,6 @@ def action_info(settings, trees, myopts, myfiles): myvars = portage.util.unique_array(myvars) use_expand = settings.get('USE_EXPAND', '').split() use_expand.sort() - use_expand_hidden = set( - settings.get('USE_EXPAND_HIDDEN', '').upper().split()) - alphabetical_use = '--alphabetical' in myopts unset_vars = [] myvars.sort() for k in myvars: @@ -1504,9 +1521,10 @@ def action_info(settings, trees, myopts, myfiles): # See if we can find any packages installed matching the strings # passed on the command line mypkgs = [] - vardb = trees[settings["ROOT"]]["vartree"].dbapi - portdb = trees[settings["ROOT"]]["porttree"].dbapi - bindb = trees[settings["ROOT"]]["bintree"].dbapi + eroot = settings['EROOT'] + vardb = trees[eroot]["vartree"].dbapi + portdb = trees[eroot]['porttree'].dbapi + bindb = trees[eroot]["bintree"].dbapi for x in myfiles: match_found = False installed_match = vardb.match(x) @@ -1541,7 +1559,6 @@ def action_info(settings, trees, myopts, myfiles): mydesiredvars = [ 'CHOST', 'CFLAGS', 'CXXFLAGS', 'LDFLAGS' ] auxkeys = mydesiredvars + list(vardb._aux_cache_keys) auxkeys.append('DEFINED_PHASES') - global_vals = {} pkgsettings = portage.config(clone=settings) # Loop through each package @@ -1611,19 +1628,19 @@ def action_info(settings, trees, myopts, myfiles): continue if pkg_type == "installed": - portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"], - pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1), - mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, + portage.doebuild(ebuildpath, "info", settings=pkgsettings, + debug=(settings.get("PORTAGE_DEBUG", "") == 1), + mydbapi=trees[settings['EROOT']]["vartree"].dbapi, tree="vartree") elif pkg_type == "ebuild": - portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"], - pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1), - mydbapi=trees[settings["ROOT"]]["porttree"].dbapi, + portage.doebuild(ebuildpath, "info", settings=pkgsettings, + debug=(settings.get("PORTAGE_DEBUG", "") == 1), + mydbapi=trees[settings['EROOT']]['porttree'].dbapi, tree="porttree") elif pkg_type == "binary": - portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"], - pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1), - mydbapi=trees[settings["ROOT"]]["bintree"].dbapi, + portage.doebuild(ebuildpath, "info", settings=pkgsettings, + debug=(settings.get("PORTAGE_DEBUG", "") == 1), + mydbapi=trees[settings['EROOT']]["bintree"].dbapi, tree="bintree") shutil.rmtree(tmpdir) @@ -1643,8 +1660,7 @@ def action_metadata(settings, portdb, myopts, porttrees=None): if not os.path.exists(cachedir): os.makedirs(cachedir) - auxdbkeys = [x for x in portage.auxdbkeys if not x.startswith("UNUSED_0")] - auxdbkeys = tuple(auxdbkeys) + auxdbkeys = portdb._known_keys class TreeData(object): __slots__ = ('dest_db', 'eclass_db', 'path', 'src_db', 'valid_nodes') @@ -1658,18 +1674,14 @@ def action_metadata(settings, portdb, myopts, porttrees=None): porttrees_data = [] for path in porttrees: src_db = portdb._pregen_auxdb.get(path) - if src_db is None and \ - os.path.isdir(os.path.join(path, 'metadata', 'cache')): - src_db = portdb.metadbmodule( - path, 'metadata/cache', auxdbkeys, readonly=True) - try: - src_db.ec = portdb._repo_info[path].eclass_db - except AttributeError: - pass + if src_db is None: + # portdbapi does not populate _pregen_auxdb + # when FEATURES=metadata-transfer is enabled + src_db = portdb._create_pregen_cache(path) if src_db is not None: porttrees_data.append(TreeData(portdb.auxdb[path], - portdb._repo_info[path].eclass_db, path, src_db)) + portdb.repositories.get_repo_for_location(path).eclass_db, path, src_db)) porttrees = [tree_data.path for tree_data in porttrees_data] @@ -1704,42 +1716,45 @@ def action_metadata(settings, portdb, myopts, porttrees=None): if onProgress is not None: onProgress(maxval, curval) - from portage.cache.util import quiet_mirroring - from portage import eapi_is_supported, \ - _validate_cache_for_unsupported_eapis - # TODO: Display error messages, but do not interfere with the progress bar. # Here's how: # 1) erase the progress bar # 2) show the error message # 3) redraw the progress bar on a new line - noise = quiet_mirroring() for cp in cp_all: for tree_data in porttrees_data: + + src_chf = tree_data.src_db.validation_chf + dest_chf = tree_data.dest_db.validation_chf + dest_chf_key = '_%s_' % dest_chf + dest_chf_getter = operator.attrgetter(dest_chf) + for cpv in portdb.cp_list(cp, mytree=tree_data.path): tree_data.valid_nodes.add(cpv) try: src = tree_data.src_db[cpv] - except KeyError as e: - noise.missing_entry(cpv) - del e + except (CacheError, KeyError): continue - except CacheError as ce: - noise.exception(cpv, ce) - del ce + + ebuild_location = portdb.findname(cpv, mytree=tree_data.path) + if ebuild_location is None: + continue + ebuild_hash = hashed_path(ebuild_location) + + try: + if not tree_data.src_db.validate_entry(src, + ebuild_hash, tree_data.eclass_db): + continue + except CacheError: continue eapi = src.get('EAPI') if not eapi: eapi = '0' - eapi = eapi.lstrip('-') eapi_supported = eapi_is_supported(eapi) if not eapi_supported: - if not _validate_cache_for_unsupported_eapis: - noise.misc(cpv, "unable to validate " + \ - "cache for EAPI='%s'" % eapi) - continue + continue dest = None try: @@ -1751,18 +1766,30 @@ def action_metadata(settings, portdb, myopts, porttrees=None): if d is not None and d.get('EAPI') in ('', '0'): del d['EAPI'] + if src_chf != 'mtime': + # src may contain an irrelevant _mtime_ which corresponds + # to the time that the cache entry was written + src.pop('_mtime_', None) + + if src_chf != dest_chf: + # populate src entry with dest_chf_key + # (the validity of the dest_chf that we generate from the + # ebuild here relies on the fact that we already used + # validate_entry to validate the ebuild with src_chf) + src[dest_chf_key] = dest_chf_getter(ebuild_hash) + if dest is not None: - if not (dest['_mtime_'] == src['_mtime_'] and \ - tree_data.eclass_db.is_eclass_data_valid( - dest['_eclasses_']) and \ + if not (dest[dest_chf_key] == src[dest_chf_key] and \ + tree_data.eclass_db.validate_and_rewrite_cache( + dest['_eclasses_'], tree_data.dest_db.validation_chf, + tree_data.dest_db.store_eclass_paths) is not None and \ set(dest['_eclasses_']) == set(src['_eclasses_'])): dest = None else: # We don't want to skip the write unless we're really # sure that the existing cache is identical, so don't # trust _mtime_ and _eclasses_ alone. - for k in set(chain(src, dest)).difference( - ('_mtime_', '_eclasses_')): + for k in auxdbkeys: if dest.get(k, '') != src.get(k, ''): dest = None break @@ -1773,56 +1800,10 @@ def action_metadata(settings, portdb, myopts, porttrees=None): continue try: - inherited = src.get('INHERITED', '') - eclasses = src.get('_eclasses_') - except CacheError as ce: - noise.exception(cpv, ce) - del ce - continue - - if eclasses is not None: - if not tree_data.eclass_db.is_eclass_data_valid( - src['_eclasses_']): - noise.eclass_stale(cpv) - continue - inherited = eclasses - else: - inherited = inherited.split() - - if tree_data.src_db.complete_eclass_entries and \ - eclasses is None: - noise.corruption(cpv, "missing _eclasses_ field") - continue - - if inherited: - # Even if _eclasses_ already exists, replace it with data from - # eclass_cache, in order to insert local eclass paths. - try: - eclasses = tree_data.eclass_db.get_eclass_data(inherited) - except KeyError: - # INHERITED contains a non-existent eclass. - noise.eclass_stale(cpv) - continue - - if eclasses is None: - noise.eclass_stale(cpv) - continue - src['_eclasses_'] = eclasses - else: - src['_eclasses_'] = {} - - if not eapi_supported: - src = { - 'EAPI' : '-' + eapi, - '_mtime_' : src['_mtime_'], - '_eclasses_' : src['_eclasses_'], - } - - try: tree_data.dest_db[cpv] = src - except CacheError as ce: - noise.exception(cpv, ce) - del ce + except CacheError: + # ignore it; can't do anything about it. + pass curval += 1 if onProgress is not None: @@ -1860,12 +1841,6 @@ def action_regen(settings, portdb, max_jobs, max_load): xterm_titles = "notitles" not in settings.features emergelog(xterm_titles, " === regen") #regenerate cache entries - try: - os.close(sys.stdin.fileno()) - except SystemExit as e: - raise # Needed else can't exit - except: - pass sys.stdout.flush() regen = MetadataRegen(portdb, max_jobs=max_jobs, max_load=max_load) @@ -1921,7 +1896,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): enter_invalid = '--ask-enter-invalid' in myopts xterm_titles = "notitles" not in settings.features emergelog(xterm_titles, " === sync") - portdb = trees[settings["ROOT"]]["porttree"].dbapi + portdb = trees[settings['EROOT']]['porttree'].dbapi myportdir = portdb.porttree_root if not myportdir: myportdir = settings.get('PORTDIR', '') @@ -1993,6 +1968,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): os.umask(0o022) dosyncuri = syncuri updatecache_flg = False + git = False if myaction == "metadata": print("skipping sync") updatecache_flg = True @@ -2021,9 +1997,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): msg = ">>> Git pull in %s successful" % myportdir emergelog(xterm_titles, msg) writemsg_level(msg + "\n") - exitcode = git_sync_timestamps(settings, myportdir) - if exitcode == os.EX_OK: - updatecache_flg = True + git = True elif syncuri[:8]=="rsync://" or syncuri[:6]=="ssh://": for vcs_dir in vcs_dirs: writemsg_level(("!!! %s appears to be under revision " + \ @@ -2050,6 +2024,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): "--whole-file", # Don't do block transfers, only entire files "--delete", # Delete files that aren't in the master tree "--stats", # Show final statistics about what was transfered + "--human-readable", "--timeout="+str(mytimeout), # IO timeout if not done in X seconds "--exclude=/distfiles", # Exclude distfiles from consideration "--exclude=/local", # Exclude local from consideration @@ -2237,7 +2212,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): print() print("Quitting.") print() - sys.exit(0) + sys.exit(128 + signal.SIGINT) emergelog(xterm_titles, ">>> Starting rsync with " + dosyncuri) if "--quiet" not in myopts: print(">>> Starting rsync with "+dosyncuri+"...") @@ -2465,17 +2440,25 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): noiselevel=-1, level=logging.ERROR) return 1 + # Reload the whole config from scratch. + settings, trees, mtimedb = load_emerge_config(trees=trees) + adjust_configs(myopts, trees) + root_config = trees[settings['EROOT']]['root_config'] + portdb = trees[settings['EROOT']]['porttree'].dbapi + + if git: + # NOTE: Do this after reloading the config, in case + # it did not exist prior to sync, so that the config + # and portdb properly account for its existence. + exitcode = git_sync_timestamps(portdb, myportdir) + if exitcode == os.EX_OK: + updatecache_flg = True + if updatecache_flg and \ myaction != "metadata" and \ "metadata-transfer" not in settings.features: updatecache_flg = False - # Reload the whole config from scratch. - settings, trees, mtimedb = load_emerge_config(trees=trees) - adjust_configs(myopts, trees) - root_config = trees[settings["ROOT"]]["root_config"] - portdb = trees[settings["ROOT"]]["porttree"].dbapi - if updatecache_flg and \ os.path.exists(os.path.join(myportdir, 'metadata', 'cache')): @@ -2489,13 +2472,13 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): # Reload the whole config from scratch. settings, trees, mtimedb = load_emerge_config(trees=trees) adjust_configs(myopts, trees) - portdb = trees[settings["ROOT"]]["porttree"].dbapi - root_config = trees[settings["ROOT"]]["root_config"] + portdb = trees[settings['EROOT']]['porttree'].dbapi + root_config = trees[settings['EROOT']]['root_config'] mybestpv = portdb.xmatch("bestmatch-visible", portage.const.PORTAGE_PACKAGE_ATOM) mypvs = portage.best( - trees[settings["ROOT"]]["vartree"].dbapi.match( + trees[settings['EROOT']]['vartree'].dbapi.match( portage.const.PORTAGE_PACKAGE_ATOM)) chk_updated_cfg_files(settings["EROOT"], @@ -2514,10 +2497,10 @@ def action_sync(settings, trees, mtimedb, myopts, myaction): if(mybestpv != mypvs) and not "--quiet" in myopts: print() - print(red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended") - print(red(" * ")+"that you update portage now, before any other packages are updated.") + print(warn(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended") + print(warn(" * ")+"that you update portage now, before any other packages are updated.") print() - print(red(" * ")+"To update portage, run 'emerge portage' now.") + print(warn(" * ")+"To update portage, run 'emerge portage' now.") print() display_news_notification(root_config, myopts) @@ -2528,7 +2511,8 @@ def action_uninstall(settings, trees, ldpath_mtimes, # For backward compat, some actions do not require leading '='. ignore_missing_eq = action in ('clean', 'unmerge') root = settings['ROOT'] - vardb = trees[root]['vartree'].dbapi + eroot = settings['EROOT'] + vardb = trees[settings['EROOT']]['vartree'].dbapi valid_atoms = [] lookup_owners = [] @@ -2566,9 +2550,9 @@ def action_uninstall(settings, trees, ldpath_mtimes, valid_atoms.append(atom) elif x.startswith(os.sep): - if not x.startswith(root): + if not x.startswith(eroot): writemsg_level(("!!! '%s' does not start with" + \ - " $ROOT.\n") % x, level=logging.ERROR, noiselevel=-1) + " $EROOT.\n") % x, level=logging.ERROR, noiselevel=-1) return 1 # Queue these up since it's most efficient to handle # multiple files in a single iter_owners() call. @@ -2661,7 +2645,7 @@ def action_uninstall(settings, trees, ldpath_mtimes, # redirection of ebuild phase output to logs as required for # options such as --quiet. sched = Scheduler(settings, trees, None, opts, - spinner) + spinner, uninstall_only=True) sched._background = sched._background_mode() sched._status_display.quiet = True @@ -2670,16 +2654,15 @@ def action_uninstall(settings, trees, ldpath_mtimes, sched.settings["PORTAGE_BACKGROUND"] = "1" sched.settings.backup_changes("PORTAGE_BACKGROUND") sched.settings.lock() - sched.pkgsettings[root] = portage.config(clone=sched.settings) + sched.pkgsettings[eroot] = portage.config(clone=sched.settings) if action in ('clean', 'unmerge') or \ (action == 'prune' and "--nodeps" in opts): # When given a list of atoms, unmerge them in the order given. ordered = action == 'unmerge' - unmerge(trees[settings["ROOT"]]['root_config'], opts, action, + rval = unmerge(trees[settings['EROOT']]['root_config'], opts, action, valid_atoms, ldpath_mtimes, ordered=ordered, scheduler=sched._sched_iface) - rval = os.EX_OK else: rval = action_depclean(settings, trees, ldpath_mtimes, opts, action, valid_atoms, spinner, scheduler=sched._sched_iface) @@ -2730,7 +2713,13 @@ def adjust_config(myopts, settings): settings["EMERGE_WARNING_DELAY"] = str(EMERGE_WARNING_DELAY) settings.backup_changes("EMERGE_WARNING_DELAY") - if "--quiet" in myopts or "--quiet-build" in myopts: + buildpkg = myopts.get("--buildpkg") + if buildpkg is True: + settings.features.add("buildpkg") + elif buildpkg == 'n': + settings.features.discard("buildpkg") + + if "--quiet" in myopts: settings["PORTAGE_QUIET"]="1" settings.backup_changes("PORTAGE_QUIET") @@ -2766,8 +2755,8 @@ def adjust_config(myopts, settings): if settings.get("NOCOLOR") not in ("yes","true"): portage.output.havecolor = 1 - """The explicit --color < y | n > option overrides the NOCOLOR environment - variable and stdout auto-detection.""" + # The explicit --color < y | n > option overrides the NOCOLOR environment + # variable and stdout auto-detection. if "--color" in myopts: if "y" == myopts["--color"]: portage.output.havecolor = 1 @@ -2806,7 +2795,7 @@ def relative_profile_path(portdir, abs_profile): profilever = None return profilever -def getportageversion(portdir, target_root, profile, chost, vardb): +def getportageversion(portdir, _unused, profile, chost, vardb): profilever = None if profile: profilever = relative_profile_path(portdir, profile) @@ -2839,7 +2828,7 @@ def getportageversion(portdir, target_root, profile, chost, vardb): for cpv in sorted(libclist): libc_split = portage.catpkgsplit(cpv)[1:] if libc_split[-1] == "r0": - libc_split[:-1] + libc_split = libc_split[:-1] libcver.append("-".join(libc_split)) else: libcver = ["unavailable"] @@ -2850,27 +2839,35 @@ def getportageversion(portdir, target_root, profile, chost, vardb): return "Portage %s (%s, %s, %s, %s)" % \ (portage.VERSION, profilever, gccver, ",".join(libcver), unameout) -def git_sync_timestamps(settings, portdir): +def git_sync_timestamps(portdb, portdir): """ Since git doesn't preserve timestamps, synchronize timestamps between entries and ebuilds/eclasses. Assume the cache has the correct timestamp for a given file as long as the file in the working tree is not modified (relative to HEAD). """ - cache_dir = os.path.join(portdir, "metadata", "cache") - if not os.path.isdir(cache_dir): - return os.EX_OK - writemsg_level(">>> Synchronizing timestamps...\n") - from portage.cache.cache_errors import CacheError + cache_db = portdb._pregen_auxdb.get(portdir) + try: - cache_db = settings.load_best_module("portdbapi.metadbmodule")( - portdir, "metadata/cache", portage.auxdbkeys[:], readonly=True) + if cache_db is None: + # portdbapi does not populate _pregen_auxdb + # when FEATURES=metadata-transfer is enabled + cache_db = portdb._create_pregen_cache(portdir) except CacheError as e: writemsg_level("!!! Unable to instantiate cache: %s\n" % (e,), level=logging.ERROR, noiselevel=-1) return 1 + if cache_db is None: + return os.EX_OK + + if cache_db.validation_chf != 'mtime': + # newer formats like md5-dict do not require mtime sync + return os.EX_OK + + writemsg_level(">>> Synchronizing timestamps...\n") + ec_dir = os.path.join(portdir, "eclass") try: ec_names = set(f[:-7] for f in os.listdir(ec_dir) \ @@ -2883,10 +2880,10 @@ def git_sync_timestamps(settings, portdir): args = [portage.const.BASH_BINARY, "-c", "cd %s && git diff-index --name-only --diff-filter=M HEAD" % \ portage._shell_quote(portdir)] - import subprocess proc = subprocess.Popen(args, stdout=subprocess.PIPE) modified_files = set(_unicode_decode(l).rstrip("\n") for l in proc.stdout) rval = proc.wait() + proc.stdout.close() if rval != os.EX_OK: return rval @@ -2990,22 +2987,15 @@ def load_emerge_config(trees=None): kwargs[k] = v trees = portage.create_trees(trees=trees, **kwargs) - for root, root_trees in trees.items(): + for root_trees in trees.values(): settings = root_trees["vartree"].settings settings._init_dirs() setconfig = load_default_config(settings, root_trees) root_trees["root_config"] = RootConfig(settings, root_trees, setconfig) - settings = trees["/"]["vartree"].settings - - for myroot in trees: - if myroot != "/": - settings = trees[myroot]["vartree"].settings - break - + settings = trees[trees._target_eroot]['vartree'].settings mtimedbfile = os.path.join(settings['EROOT'], portage.CACHE_PATH, "mtimedb") mtimedb = portage.MtimeDB(mtimedbfile) - portage.output._init(config_root=settings['PORTAGE_CONFIGROOT']) QueryCommand._db = trees return settings, trees, mtimedb @@ -3015,55 +3005,35 @@ def chk_updated_cfg_files(eroot, config_protect): portage.util.find_updated_config_files(target_root, config_protect)) for x in result: - writemsg_level("\n %s " % (colorize("WARN", "* IMPORTANT:"),), + 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], + 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, + 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" % \ + 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.") + 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): - target_root = root_config.settings['EROOT'] - trees = root_config.trees - settings = trees["vartree"].settings - portdb = trees["porttree"].dbapi - vardb = trees["vartree"].dbapi - NEWS_PATH = os.path.join("metadata", "news") - UNREAD_PATH = os.path.join(target_root, NEWS_LIB_PATH, "news") - newsReaderDisplay = False - update = "--pretend" not in myopts - if "news" not in settings.features: + if "news" not in root_config.settings.features: return - - for repo in portdb.getRepositories(): - unreadItems = checkUpdatedNewsItems( - portdb, vardb, NEWS_PATH, UNREAD_PATH, repo, update=update) - if unreadItems: - if not newsReaderDisplay: - newsReaderDisplay = True - print() - print(colorize("WARN", " * IMPORTANT:"), end=' ') - print("%s news items need reading for repository '%s'." % (unreadItems, repo)) - - - if newsReaderDisplay: - print(colorize("WARN", " *"), end=' ') - print("Use " + colorize("GOOD", "eselect news") + " to read news items.") - print() + 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): """ @@ -3071,7 +3041,7 @@ def getgccversion(chost): return: the current in-use gcc version """ - gcc_ver_command = 'gcc -dumpversion' + gcc_ver_command = ['gcc', '-dumpversion'] gcc_ver_prefix = 'gcc-' gcc_not_found_error = red( @@ -3080,44 +3050,42 @@ def getgccversion(chost): "!!! other terminals also.\n" ) - mystatus, myoutput = subprocess_getstatusoutput("gcc-config -c") + try: + proc = subprocess.Popen(["gcc-config", "-c"], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError: + myoutput = None + mystatus = 1 + else: + myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n") + mystatus = proc.wait() if mystatus == os.EX_OK and myoutput.startswith(chost + "-"): return myoutput.replace(chost + "-", gcc_ver_prefix, 1) - mystatus, myoutput = subprocess_getstatusoutput( - chost + "-" + gcc_ver_command) + try: + proc = subprocess.Popen( + [chost + "-" + gcc_ver_command[0]] + gcc_ver_command[1:], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError: + myoutput = None + mystatus = 1 + else: + myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n") + mystatus = proc.wait() if mystatus == os.EX_OK: return gcc_ver_prefix + myoutput - mystatus, myoutput = subprocess_getstatusoutput(gcc_ver_command) + try: + proc = subprocess.Popen(gcc_ver_command, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError: + myoutput = None + mystatus = 1 + else: + myoutput = _unicode_decode(proc.communicate()[0]).rstrip("\n") + mystatus = proc.wait() if mystatus == os.EX_OK: return gcc_ver_prefix + myoutput portage.writemsg(gcc_not_found_error, noiselevel=-1) return "[unavailable]" - -def checkUpdatedNewsItems(portdb, vardb, NEWS_PATH, UNREAD_PATH, repo_id, - update=False): - """ - Examines news items in repodir + '/' + NEWS_PATH and attempts to find unread items - Returns the number of unread (yet relevent) items. - - @param portdb: a portage tree database - @type portdb: pordbapi - @param vardb: an installed package database - @type vardb: vardbapi - @param NEWS_PATH: - @type NEWS_PATH: - @param UNREAD_PATH: - @type UNREAD_PATH: - @param repo_id: - @type repo_id: - @rtype: Integer - @returns: - 1. The number of unread but relevant news items. - - """ - from portage.news import NewsManager - manager = NewsManager(portdb, vardb, NEWS_PATH, UNREAD_PATH) - return manager.getUnreadItems( repo_id, update=update ) - |