4 from optparse import OptionParser, OptionValueError
5 if not hasattr(__builtins__, "set"):
6 from sets import Set as set
11 from os import path as osp
12 sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
15 import portage.const, portage.exception
16 class WorldHandler(object):
20 name = staticmethod(name)
24 self.not_installed = []
25 self.invalid_category = []
27 self.world_file = os.path.join("/", portage.const.WORLD_FILE)
28 self.found = os.access(self.world_file, os.R_OK)
30 def _check_world(self, onProgress):
31 categories = set(portage.settings.categories)
32 myroot = portage.settings["ROOT"]
33 vardb = portage.db[myroot]["vartree"].dbapi
35 world_atoms = open(self.world_file).read().split()
36 maxval = len(world_atoms)
39 for i, atom in enumerate(world_atoms):
40 if not portage.isvalidatom(atom):
41 self.invalid.append(atom)
43 onProgress(maxval, i+1)
46 if not vardb.match(atom):
47 self.not_installed.append(atom)
49 if portage.catsplit(atom)[0] not in categories:
50 self.invalid_category.append(atom)
53 self.okay.append(atom)
55 onProgress(maxval, i+1)
57 def check(self, onProgress=None):
58 self._check_world(onProgress)
61 errors += map(lambda x: "'%s' is not a valid atom" % x, self.invalid)
62 errors += map(lambda x: "'%s' is not installed" % x, self.not_installed)
63 errors += map(lambda x: "'%s' has a category that is not listed in /etc/portage/categories" % x, self.invalid_category)
65 errors.append(self.world_file + " could not be opened for reading")
68 def fix(self, onProgress=None):
69 self._check_world(onProgress)
72 portage.write_atomic(self.world_file, "\n".join(self.okay))
73 except portage.exception.PortageException:
74 errors.append(self.world_file + " could not be opened for writing")
77 class VdbKeyHandler(object):
80 name = staticmethod(name)
83 self.list = portage.db["/"]["vartree"].dbapi.cpv_all()
85 self.keys = ["HOMEPAGE", "SRC_URI", "KEYWORDS", "DESCRIPTION"]
88 mydir = os.path.join(os.sep, portage.settings["ROOT"], portage.const.VDB_PATH, p)+os.sep
91 if os.path.exists(mydir+k):
95 self.missing.append(p)
98 return ["%s has missing keys" % x for x in self.missing]
104 for p in self.missing:
105 mydir = os.path.join(os.sep, portage.settings["ROOT"], portage.const.VDB_PATH, p)+os.sep
106 if not os.access(mydir+"environment.bz2", os.R_OK):
107 errors.append("Can't access %s" % (mydir+"environment.bz2"))
108 elif not os.access(mydir, os.W_OK):
109 errors.append("Can't create files in %s" % mydir)
111 env = os.popen("bzip2 -dcq "+mydir+"environment.bz2", "r")
112 envlines = env.read().split("\n")
115 s = [l for l in envlines if l.startswith(k+"=")]
117 errors.append("multiple matches for %s found in %senvironment.bz2" % (k, mydir))
121 s = s[0].split("=",1)[1]
122 s = s.lstrip("$").strip("\'\"")
123 s = re.sub("(\\\\[nrt])+", " ", s)
124 s = " ".join(s.split()).strip()
127 keyfile = open(mydir+os.sep+k, "w")
128 keyfile.write(s+"\n")
130 except (IOError, OSError), e:
131 errors.append("Could not write %s, reason was: %s" % (mydir+k, e))
135 def emaint_main(myargv):
137 # TODO: Create a system that allows external modules to be added without
138 # the need for hard coding.
139 modules = {"world" : WorldHandler}
141 module_names = modules.keys()
143 module_names.insert(0, "all")
145 def exclusive(option, *args, **kw):
146 var = kw.get("var", None)
148 raise ValueError("var not specified to exclusive()")
149 if getattr(parser, var, ""):
150 raise OptionValueError("%s and %s are exclusive options" % (getattr(parser, var), option))
151 setattr(parser, var, str(option))
154 usage = "usage: emaint [options] " + " | ".join(module_names)
156 usage+= "\n\nCurrently emaint can only check and fix problems with one's world\n"
157 usage+= "file. Future versions will integrate other portage check-and-fix\n"
158 usage+= "tools and provide a single interface to system health checks."
161 parser = OptionParser(usage=usage)
162 parser.add_option("-c", "--check", help="check for problems",
163 action="callback", callback=exclusive, callback_kwargs={"var":"action"})
164 parser.add_option("-f", "--fix", help="attempt to fix problems",
165 action="callback", callback=exclusive, callback_kwargs={"var":"action"})
169 (options, args) = parser.parse_args(args=myargv)
171 parser.error("Incorrect number of arguments")
172 if args[0] not in module_names:
173 parser.error("%s target is not a known target" % args[0])
176 action = parser.action
178 print "Defaulting to --check"
179 action = "-c/--check"
182 tasks = modules.values()
184 tasks = [modules[args[0]]]
187 if action == "-c/--check":
188 status = "Checking %s for problems"
191 status = "Attempting to fix %s"
196 print status % task.name()
198 result = getattr(inst, func)()
201 print "\n".join(result)
206 if __name__ == "__main__":
207 emaint_main(sys.argv[1:])