From: Fabian Groffen Date: Sun, 12 Aug 2012 07:49:56 +0000 (+0200) Subject: Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=20e5636d6a423452434ede1819e120133a9229ed;p=portage.git Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix Conflicts: bin/chpathtool.py bin/repoman --- 20e5636d6a423452434ede1819e120133a9229ed diff --cc bin/chpathtool.py index 1ae4e7c19,85e608ea9..be42bb063 --- a/bin/chpathtool.py +++ b/bin/chpathtool.py @@@ -1,5 -1,5 +1,5 @@@ -#!/usr/bin/python +#!@PREFIX_PORTAGE_PYTHON@ - # Copyright 2011 Gentoo Foundation + # Copyright 2011-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import io diff --cc bin/emaint index 37a3248ec,bee46c40d..ab21742a5 --- a/bin/emaint +++ b/bin/emaint @@@ -2,649 -2,44 +2,46 @@@ # Copyright 2005-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 + """'The emaint program provides an interface to system health + checks and maintenance. + """ + from __future__ import print_function - import errno - import re - import signal - import stat import sys - import textwrap - import time - from optparse import OptionParser, OptionValueError + import errno + # This block ensures that ^C interrupts are handled quietly. + try: + import signal + + def exithandler(signum,frame): + signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGTERM, signal.SIG_IGN) + sys.exit(1) + + signal.signal(signal.SIGINT, exithandler) + signal.signal(signal.SIGTERM, exithandler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + except KeyboardInterrupt: + sys.exit(1) -try: - import portage -except ImportError: - from os import path as osp - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) - import portage +# for an explanation on this logic, see pym/_emerge/__init__.py +import os +import sys +if os.environ.__contains__("PORTAGE_PYTHONPATH"): + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"]) +else: + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym")) +import portage - from portage import os - from portage.util import writemsg - - if sys.hexversion >= 0x3000000: - long = int - - class WorldHandler(object): - - short_desc = "Fix problems in the world file" - - def name(): - return "world" - name = staticmethod(name) - - def __init__(self): - self.invalid = [] - self.not_installed = [] - self.okay = [] - from portage._sets import load_default_config - setconfig = load_default_config(portage.settings, - portage.db[portage.settings['EROOT']]) - self._sets = setconfig.getSets() - - def _check_world(self, onProgress): - eroot = portage.settings['EROOT'] - self.world_file = os.path.join(eroot, portage.const.WORLD_FILE) - self.found = os.access(self.world_file, os.R_OK) - vardb = portage.db[eroot]["vartree"].dbapi - - from portage._sets import SETPREFIX - sets = self._sets - world_atoms = list(sets["selected"]) - maxval = len(world_atoms) - if onProgress: - onProgress(maxval, 0) - for i, atom in enumerate(world_atoms): - if not isinstance(atom, portage.dep.Atom): - if atom.startswith(SETPREFIX): - s = atom[len(SETPREFIX):] - if s in sets: - self.okay.append(atom) - else: - self.not_installed.append(atom) - else: - self.invalid.append(atom) - if onProgress: - onProgress(maxval, i+1) - continue - okay = True - if not vardb.match(atom): - self.not_installed.append(atom) - okay = False - if okay: - self.okay.append(atom) - if onProgress: - onProgress(maxval, i+1) - - def check(self, onProgress=None): - self._check_world(onProgress) - errors = [] - if self.found: - errors += ["'%s' is not a valid atom" % x for x in self.invalid] - errors += ["'%s' is not installed" % x for x in self.not_installed] - else: - errors.append(self.world_file + " could not be opened for reading") - return errors - - def fix(self, onProgress=None): - world_set = self._sets["selected"] - world_set.lock() - try: - world_set.load() # maybe it's changed on disk - before = set(world_set) - self._check_world(onProgress) - after = set(self.okay) - errors = [] - if before != after: - try: - world_set.replace(self.okay) - except portage.exception.PortageException: - errors.append("%s could not be opened for writing" % \ - self.world_file) - return errors - finally: - world_set.unlock() - - class BinhostHandler(object): - - short_desc = "Generate a metadata index for binary packages" - - def name(): - return "binhost" - name = staticmethod(name) - - def __init__(self): - eroot = portage.settings['EROOT'] - self._bintree = portage.db[eroot]["bintree"] - self._bintree.populate() - self._pkgindex_file = self._bintree._pkgindex_file - self._pkgindex = self._bintree._load_pkgindex() - - def _need_update(self, cpv, data): - - if "MD5" not in data: - return True - - size = data.get("SIZE") - if size is None: - return True - - mtime = data.get("MTIME") - if mtime is None: - return True - - pkg_path = self._bintree.getname(cpv) - try: - s = os.lstat(pkg_path) - except OSError as e: - if e.errno not in (errno.ENOENT, errno.ESTALE): - raise - # We can't update the index for this one because - # it disappeared. - return False - - try: - if long(mtime) != s[stat.ST_MTIME]: - return True - if long(size) != long(s.st_size): - return True - except ValueError: - return True - - return False - - def check(self, onProgress=None): - missing = [] - cpv_all = self._bintree.dbapi.cpv_all() - cpv_all.sort() - maxval = len(cpv_all) - if onProgress: - onProgress(maxval, 0) - pkgindex = self._pkgindex - missing = [] - metadata = {} - for d in pkgindex.packages: - metadata[d["CPV"]] = d - for i, cpv in enumerate(cpv_all): - d = metadata.get(cpv) - if not d or self._need_update(cpv, d): - missing.append(cpv) - if onProgress: - onProgress(maxval, i+1) - errors = ["'%s' is not in Packages" % cpv for cpv in missing] - stale = set(metadata).difference(cpv_all) - for cpv in stale: - errors.append("'%s' is not in the repository" % cpv) - return errors - - def fix(self, onProgress=None): - bintree = self._bintree - cpv_all = self._bintree.dbapi.cpv_all() - cpv_all.sort() - missing = [] - maxval = 0 - if onProgress: - onProgress(maxval, 0) - pkgindex = self._pkgindex - missing = [] - metadata = {} - for d in pkgindex.packages: - metadata[d["CPV"]] = d - - for i, cpv in enumerate(cpv_all): - d = metadata.get(cpv) - if not d or self._need_update(cpv, d): - missing.append(cpv) - - stale = set(metadata).difference(cpv_all) - if missing or stale: - from portage import locks - pkgindex_lock = locks.lockfile( - self._pkgindex_file, wantnewlockfile=1) - try: - # Repopulate with lock held. - bintree._populate() - cpv_all = self._bintree.dbapi.cpv_all() - cpv_all.sort() - - pkgindex = bintree._load_pkgindex() - self._pkgindex = pkgindex - - metadata = {} - for d in pkgindex.packages: - metadata[d["CPV"]] = d - - # Recount missing packages, with lock held. - del missing[:] - for i, cpv in enumerate(cpv_all): - d = metadata.get(cpv) - if not d or self._need_update(cpv, d): - missing.append(cpv) - - maxval = len(missing) - for i, cpv in enumerate(missing): - try: - metadata[cpv] = bintree._pkgindex_entry(cpv) - except portage.exception.InvalidDependString: - writemsg("!!! Invalid binary package: '%s'\n" % \ - bintree.getname(cpv), noiselevel=-1) - - if onProgress: - onProgress(maxval, i+1) - - for cpv in set(metadata).difference( - self._bintree.dbapi.cpv_all()): - del metadata[cpv] - - # We've updated the pkgindex, so set it to - # repopulate when necessary. - bintree.populated = False - - del pkgindex.packages[:] - pkgindex.packages.extend(metadata.values()) - from portage.util import atomic_ofstream - f = atomic_ofstream(self._pkgindex_file) - try: - self._pkgindex.write(f) - finally: - f.close() - finally: - locks.unlockfile(pkgindex_lock) - - if onProgress: - if maxval == 0: - maxval = 1 - onProgress(maxval, maxval) - return None - - class MoveHandler(object): - - def __init__(self, tree, porttree): - self._tree = tree - self._portdb = porttree.dbapi - self._update_keys = ["DEPEND", "RDEPEND", "PDEPEND", "PROVIDE"] - self._master_repo = \ - self._portdb.getRepositoryName(self._portdb.porttree_root) - - def _grab_global_updates(self): - from portage.update import grab_updates, parse_updates - retupdates = {} - errors = [] - - for repo_name in self._portdb.getRepositories(): - repo = self._portdb.getRepositoryPath(repo_name) - updpath = os.path.join(repo, "profiles", "updates") - if not os.path.isdir(updpath): - continue - - try: - rawupdates = grab_updates(updpath) - except portage.exception.DirectoryNotFound: - rawupdates = [] - upd_commands = [] - for mykey, mystat, mycontent in rawupdates: - commands, errors = parse_updates(mycontent) - upd_commands.extend(commands) - errors.extend(errors) - retupdates[repo_name] = upd_commands - - if self._master_repo in retupdates: - retupdates['DEFAULT'] = retupdates[self._master_repo] - - return retupdates, errors + from portage.emaint.main import emaint_main - def check(self, onProgress=None): - allupdates, errors = self._grab_global_updates() - # Matching packages and moving them is relatively fast, so the - # progress bar is updated in indeterminate mode. - match = self._tree.dbapi.match - aux_get = self._tree.dbapi.aux_get - if onProgress: - onProgress(0, 0) - for repo, updates in allupdates.items(): - if repo == 'DEFAULT': - continue - if not updates: - continue - - def repo_match(repository): - return repository == repo or \ - (repo == self._master_repo and \ - repository not in allupdates) - - for i, update_cmd in enumerate(updates): - if update_cmd[0] == "move": - origcp, newcp = update_cmd[1:] - for cpv in match(origcp): - if repo_match(aux_get(cpv, ["repository"])[0]): - errors.append("'%s' moved to '%s'" % (cpv, newcp)) - elif update_cmd[0] == "slotmove": - pkg, origslot, newslot = update_cmd[1:] - for cpv in match(pkg): - slot, prepo = aux_get(cpv, ["SLOT", "repository"]) - if slot == origslot and repo_match(prepo): - errors.append("'%s' slot moved from '%s' to '%s'" % \ - (cpv, origslot, newslot)) - if onProgress: - onProgress(0, 0) - - # Searching for updates in all the metadata is relatively slow, so this - # is where the progress bar comes out of indeterminate mode. - cpv_all = self._tree.dbapi.cpv_all() - cpv_all.sort() - maxval = len(cpv_all) - aux_update = self._tree.dbapi.aux_update - meta_keys = self._update_keys + ['repository', 'EAPI'] - if onProgress: - onProgress(maxval, 0) - for i, cpv in enumerate(cpv_all): - metadata = dict(zip(meta_keys, aux_get(cpv, meta_keys))) - eapi = metadata.pop('EAPI') - repository = metadata.pop('repository') - try: - updates = allupdates[repository] - except KeyError: - try: - updates = allupdates['DEFAULT'] - except KeyError: - continue - if not updates: - continue - metadata_updates = \ - portage.update_dbentries(updates, metadata, eapi=eapi) - if metadata_updates: - errors.append("'%s' has outdated metadata" % cpv) - if onProgress: - onProgress(maxval, i+1) - return errors - - def fix(self, onProgress=None): - allupdates, errors = self._grab_global_updates() - # Matching packages and moving them is relatively fast, so the - # progress bar is updated in indeterminate mode. - move = self._tree.dbapi.move_ent - slotmove = self._tree.dbapi.move_slot_ent - if onProgress: - onProgress(0, 0) - for repo, updates in allupdates.items(): - if repo == 'DEFAULT': - continue - if not updates: - continue - - def repo_match(repository): - return repository == repo or \ - (repo == self._master_repo and \ - repository not in allupdates) - - for i, update_cmd in enumerate(updates): - if update_cmd[0] == "move": - move(update_cmd, repo_match=repo_match) - elif update_cmd[0] == "slotmove": - slotmove(update_cmd, repo_match=repo_match) - if onProgress: - onProgress(0, 0) - - # Searching for updates in all the metadata is relatively slow, so this - # is where the progress bar comes out of indeterminate mode. - self._tree.dbapi.update_ents(allupdates, onProgress=onProgress) - return errors - - class MoveInstalled(MoveHandler): - - short_desc = "Perform package move updates for installed packages" - - def name(): - return "moveinst" - name = staticmethod(name) - def __init__(self): - eroot = portage.settings['EROOT'] - MoveHandler.__init__(self, portage.db[eroot]["vartree"], portage.db[eroot]["porttree"]) - - class MoveBinary(MoveHandler): - - short_desc = "Perform package move updates for binary packages" - - def name(): - return "movebin" - name = staticmethod(name) - def __init__(self): - eroot = portage.settings['EROOT'] - MoveHandler.__init__(self, portage.db[eroot]["bintree"], portage.db[eroot]['porttree']) - - class VdbKeyHandler(object): - def name(): - return "vdbkeys" - name = staticmethod(name) - - def __init__(self): - self.list = portage.db[portage.settings["EROOT"]]["vartree"].dbapi.cpv_all() - self.missing = [] - self.keys = ["HOMEPAGE", "SRC_URI", "KEYWORDS", "DESCRIPTION"] - - for p in self.list: - mydir = os.path.join(portage.settings["EROOT"], portage.const.VDB_PATH, p)+os.sep - ismissing = True - for k in self.keys: - if os.path.exists(mydir+k): - ismissing = False - break - if ismissing: - self.missing.append(p) - - def check(self): - return ["%s has missing keys" % x for x in self.missing] - - def fix(self): - - errors = [] - - for p in self.missing: - mydir = os.path.join(portage.settings["EROOT"], portage.const.VDB_PATH, p)+os.sep - if not os.access(mydir+"environment.bz2", os.R_OK): - errors.append("Can't access %s" % (mydir+"environment.bz2")) - elif not os.access(mydir, os.W_OK): - errors.append("Can't create files in %s" % mydir) - else: - env = os.popen("bzip2 -dcq "+mydir+"environment.bz2", "r") - envlines = env.read().split("\n") - env.close() - for k in self.keys: - s = [l for l in envlines if l.startswith(k+"=")] - if len(s) > 1: - errors.append("multiple matches for %s found in %senvironment.bz2" % (k, mydir)) - elif len(s) == 0: - s = "" - else: - s = s[0].split("=",1)[1] - s = s.lstrip("$").strip("\'\"") - s = re.sub("(\\\\[nrt])+", " ", s) - s = " ".join(s.split()).strip() - if s != "": - try: - keyfile = open(mydir+os.sep+k, "w") - keyfile.write(s+"\n") - keyfile.close() - except (IOError, OSError) as e: - errors.append("Could not write %s, reason was: %s" % (mydir+k, e)) - - return errors - - class ProgressHandler(object): - def __init__(self): - self.curval = 0 - self.maxval = 0 - self.last_update = 0 - self.min_display_latency = 0.2 - - def onProgress(self, maxval, curval): - self.maxval = maxval - self.curval = curval - cur_time = time.time() - if cur_time - self.last_update >= self.min_display_latency: - self.last_update = cur_time - self.display() - - def display(self): - raise NotImplementedError(self) - - class CleanResume(object): - - short_desc = "Discard emerge --resume merge lists" - - def name(): - return "cleanresume" - name = staticmethod(name) - - def check(self, onProgress=None): - messages = [] - mtimedb = portage.mtimedb - resume_keys = ("resume", "resume_backup") - maxval = len(resume_keys) - if onProgress: - onProgress(maxval, 0) - for i, k in enumerate(resume_keys): - try: - d = mtimedb.get(k) - if d is None: - continue - if not isinstance(d, dict): - messages.append("unrecognized resume list: '%s'" % k) - continue - mergelist = d.get("mergelist") - if mergelist is None or not hasattr(mergelist, "__len__"): - messages.append("unrecognized resume list: '%s'" % k) - continue - messages.append("resume list '%s' contains %d packages" % \ - (k, len(mergelist))) - finally: - if onProgress: - onProgress(maxval, i+1) - return messages - - def fix(self, onProgress=None): - delete_count = 0 - mtimedb = portage.mtimedb - resume_keys = ("resume", "resume_backup") - maxval = len(resume_keys) - if onProgress: - onProgress(maxval, 0) - for i, k in enumerate(resume_keys): - try: - if mtimedb.pop(k, None) is not None: - delete_count += 1 - finally: - if onProgress: - onProgress(maxval, i+1) - if delete_count: - mtimedb.commit() - - def emaint_main(myargv): - - # Similar to emerge, emaint needs a default umask so that created - # files (such as the world file) have sane permissions. - os.umask(0o22) - - # TODO: Create a system that allows external modules to be added without - # the need for hard coding. - modules = { - "world" : WorldHandler, - "binhost":BinhostHandler, - "moveinst":MoveInstalled, - "movebin":MoveBinary, - "cleanresume":CleanResume - } - - module_names = list(modules) - module_names.sort() - module_names.insert(0, "all") - - def exclusive(option, *args, **kw): - var = kw.get("var", None) - if var is None: - raise ValueError("var not specified to exclusive()") - if getattr(parser, var, ""): - raise OptionValueError("%s and %s are exclusive options" % (getattr(parser, var), option)) - setattr(parser, var, str(option)) - - - usage = "usage: emaint [options] COMMAND" - - desc = "The emaint program provides an interface to system health " + \ - "checks and maintenance. See the emaint(1) man page " + \ - "for additional information about the following commands:" - - usage += "\n\n" - for line in textwrap.wrap(desc, 65): - usage += "%s\n" % line - usage += "\n" - usage += " %s" % "all".ljust(15) + \ - "Perform all supported commands\n" - for m in module_names[1:]: - usage += " %s%s\n" % (m.ljust(15), modules[m].short_desc) - - parser = OptionParser(usage=usage, version=portage.VERSION) - parser.add_option("-c", "--check", help="check for problems", - action="callback", callback=exclusive, callback_kwargs={"var":"action"}) - parser.add_option("-f", "--fix", help="attempt to fix problems", - action="callback", callback=exclusive, callback_kwargs={"var":"action"}) - parser.action = None - - - (options, args) = parser.parse_args(args=myargv) - if len(args) != 1: - parser.error("Incorrect number of arguments") - if args[0] not in module_names: - parser.error("%s target is not a known target" % args[0]) - - if parser.action: - action = parser.action - else: - print("Defaulting to --check") - action = "-c/--check" - - if args[0] == "all": - tasks = modules.values() - else: - tasks = [modules[args[0]]] - - - if action == "-c/--check": - func = "check" - else: - func = "fix" - - isatty = os.environ.get('TERM') != 'dumb' and sys.stdout.isatty() - for task in tasks: - inst = task() - onProgress = None - if isatty: - progressBar = portage.output.TermProgressBar(title="Emaint", max_desc_length=26) - progressHandler = ProgressHandler() - onProgress = progressHandler.onProgress - def display(): - progressBar.set(progressHandler.curval, progressHandler.maxval) - progressHandler.display = display - def sigwinch_handler(signum, frame): - lines, progressBar.term_columns = \ - portage.output.get_term_size() - signal.signal(signal.SIGWINCH, sigwinch_handler) - progressBar.label(func + " " + inst.name()) - result = getattr(inst, func)(onProgress=onProgress) - if isatty: - # make sure the final progress is displayed - progressHandler.display() - print() - signal.signal(signal.SIGWINCH, signal.SIG_DFL) - if result: - print() - print("\n".join(result)) - print("\n") - - print("Finished") - - if __name__ == "__main__": + try: emaint_main(sys.argv[1:]) + except IOError as e: + if e.errno == errno.EACCES: + print("\nemaint: Need superuser access") + sys.exit(1) + else: + raise diff --cc bin/repoman index ed6187d01,b50fac82c..7223b8d48 --- a/bin/repoman +++ b/bin/repoman @@@ -424,8 -420,6 +423,7 @@@ qawarnings = set( "KEYWORDS.dropped", "KEYWORDS.stupid", "KEYWORDS.missing", +"IUSE.invalid", - "IUSE.undefined", "PDEPEND.suspect", "RDEPEND.implicit", "RDEPEND.suspect", diff --cc cnf/make.globals index dc3eac966,ce3555470..81c1282b6 --- a/cnf/make.globals +++ b/cnf/make.globals @@@ -144,11 -121,11 +144,11 @@@ PORTAGE_WORKDIR_MODE="0700 # Some defaults for elog PORTAGE_ELOG_CLASSES="log warn error" - PORTAGE_ELOG_SYSTEM="save_summary echo" + PORTAGE_ELOG_SYSTEM="save_summary:log,warn,error,qa echo" -PORTAGE_ELOG_MAILURI="root" +PORTAGE_ELOG_MAILURI="@rootuser@" PORTAGE_ELOG_MAILSUBJECT="[portage] ebuild log for \${PACKAGE} on \${HOST}" -PORTAGE_ELOG_MAILFROM="portage@localhost" +PORTAGE_ELOG_MAILFROM="@portageuser@@localhost" # Signing command used by repoman PORTAGE_GPG_SIGNING_COMMAND="gpg --sign --digest-algo SHA256 --clearsign --yes --default-key \"\${PORTAGE_GPG_KEY}\" --homedir \"\${PORTAGE_GPG_DIR}\" \"\${FILE}\""