#!/usr/bin/python -O import sys from copy import copy from optparse import OptionParser, OptionValueError import os, portage, portage_const class WorldHandler(object): def name(): return "world" name = staticmethod(name) def __init__(self): self.invalid = [] self.not_installed = [] self.masked = [] self.unavailable = [] self.okay = [] self.found = os.access(portage_const.WORLD_FILE, os.R_OK) for atom in open(portage_const.WORLD_FILE).read().split(): if not portage.isvalidatom(atom): self.invalid.append(atom) elif not portage.db["/"]["vartree"].dbapi.match(atom): self.not_installed.append(atom) elif not portage.db["/"]["porttree"].dbapi.xmatch("match-all", atom): self.unavailable.append(atom) elif not portage.db["/"]["porttree"].dbapi.match("match-visible", atom): self.masked.append(atom) else: self.okay.append(atom) def check(self): errors = [] if self.found: errors += map(lambda x: "'%s' is not a valid atom" % x, self.invalid) errors += map(lambda x: "'%s' is not installed" % x, self.not_installed) errors += map(lambda x: "'%s' is masked (manually fix by adding to package.keywords)" % x, self.masked) errors += map(lambda x: "'%s' has no ebuilds available" % x, self.unavailable) if self.masked: errors += "Masked ebuilds can be manually unmasked with package.keywords or package.unmask" else: errors.append(portage_const.WORLD_FILE + " could not be opened for reading") return errors def fix(self): errors = [] try: open(portage_const.WORLD_FILE, "w").write("\n".join(self.okay)) except OSError: errors.append(portage_const.WORLD_FILE + " could not be opened for writing") return errors modules = {"world" : WorldHandler} module_names = modules.keys() module_names.sort() module_names.insert(0, "all") def exclusive(option, unused1, unused2, unused3, var=None): if not var: 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] " + " | ".join(module_names) usage+= "\n\nCurrently emaint can only check and fix problems with one's world\n" usage+= "file. Future versions will integrate other portage check-and-fix\n" usage+= "tools and provide a single interface to system health checks." parser = OptionParser(usage=usage) 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() 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": status = "Checking %s for problems" func = "check" else: status = "Attempting to fix %s" func = "fix" for task in tasks: print status % task.name() inst = task() result = getattr(inst, func)() if result: print print "\n".join(result) print "\n" print "Finished"