#!/usr/bin/python # -*- coding: utf-8 -*- import shutil import sys import re import os from optparse import OptionParser def read_file(path): with open(path) as f: return f.read().strip() def write_file(path, content): open(path, "w").write(content) open(path, "a").write("\n") class Components(): COMPONENT_XML = """ %s """ EMPTY_COMPONENT = """ %s FIXME FIXME FIXME FIXME PisiLinux Community admins@pisilinux.org """ CBGN = """ """ CEND = """ """ LOCALNAME = ' %s\n' SUMMARY = ' %s\n' DESCRIPTION = ' %s\n' COMPONENT = """ %s %s%s%s %s %s %s """ def __init__(self, path): self.path = path self.components = [] self.components_xml = "%s/components.xml" % self.path self.name_ptrn = re.compile("\s*(.+?)<\/Name>\s*") self.lnamech_ptrn = re.compile("\s*(.+?)<\/LocalName>\s*") self.lname_ptrn = re.compile("\s*(.+?)<\/LocalName>\s*") self.summarych_ptrn = re.compile("\s*(.+?)<\/Summary>\s*") self.summary_ptrn = re.compile("\s*(.+?)<\/Summary>\s*") self.descch_ptrn = re.compile("\s*(.+?)<\/Description>\s*") self.desc_ptrn = re.compile("\s*(.+?)<\/Description>\s*") self.group_ptrn = re.compile("\s*(.+?)<\/Group>\s*") self.email_ptrn = re.compile("\s*(.+?)<\/Email>\s*") self.cbgn_ptrn = re.compile("\s*\s*") self.cend_ptrn = re.compile("\s*<\/Component>\s*") self.mbgn_ptrn = re.compile("\s*\s*") self.mend_ptrn = re.compile("\s*<\/Maintainer>\s*") self.csend_ptrn = re.compile("\s*<\/Components>\s*") def read_components(self): csfile = read_file(self.components_xml) cread = False mread = False component = {} for line in csfile.split("\n"): if re.search(self.cbgn_ptrn, line): cread = True component["err"] = [] component["unknown"] = [] component["clname"] = [] component["csummary"] = [] component["cdesc"] = [] continue elif re.search(self.cend_ptrn, line): cread = False self.components.append(component) component = {} continue if cread: if re.search(self.mbgn_ptrn, line): mread = True continue elif re.search(self.mend_ptrn, line): mread = False continue elif re.search(self.name_ptrn, line): if mread: component["mname"] = re.sub(self.name_ptrn, r"\1", line) else: component["cname"] = re.sub(self.name_ptrn, r"\1", line) elif re.search(self.lnamech_ptrn, line): if re.search(self.lname_ptrn, line): component["clname"].append(re.sub(self.lname_ptrn, r"\1:\2", line)) else: component["err"].append("LocalName") elif re.search(self.summarych_ptrn, line): if re.search(self.summary_ptrn, line): component["csummary"].append(re.sub(self.summary_ptrn, r"\1:\2", line)) else: component["err"].append("Summary") elif re.search(self.descch_ptrn, line): if re.search(self.desc_ptrn, line): component["cdesc"].append(re.sub(self.desc_ptrn, r"\1:\2", line)) else: component["err"].append("Description") elif re.search(self.group_ptrn, line): component["cgroup"] = re.sub(self.group_ptrn, r"\1", line) elif re.search(self.email_ptrn, line): component["memail"] = re.sub(self.email_ptrn, r"\1", line) else: component["unknown"].append(line) def sort_components(self): self.components = sorted(self.components, key=lambda k: k['cname']) def backup_components(self): files = os.walk(self.path).next()[2] last = 0 for f in files: if f.startswith("components.xml.") and int(f[-3:]) > last: last = int(f[-3:]) last = str(last + 1) while len(last) < 3: last = "0" + last shutil.copyfile(self.components_xml, ".".join((self.components_xml, last))) def write_components(self): self.sort_components() cs = '' for c in self.components: ln = "" for i in c["clname"]: ln += self.LOCALNAME % tuple(i.split(":")) s = "" for i in c["csummary"]: s += self.SUMMARY % tuple(i.split(":")) d = "" for i in c["cdesc"]: d += self.DESCRIPTION % tuple(i.split(":")) cs += self.COMPONENT % (c["cname"], ln, s, d, c["cgroup"], c["mname"], c["memail"]) self.backup_components() open(self.components_xml, "w").write(self.CBGN) open(self.components_xml, "a").write(cs) open(self.components_xml, "a").write(self.CEND) open(self.components_xml, "a").write("\n") def edit(self): l = [] mcommands = {"q": "quit", "l": "list components", "c": "choose component", "h": "help"} ecommands = {"mn": "set maintainer name", "me": "set maintainer email", "ln": "set local name (lang:name)", "s": "set summary (lang:summary)", "d": "set description (lang:description)", "m": "main menu", "w": "write", "h": "help"} def read_command(m): opts = mcommands.keys() if m == "m" else ecommands.keys() return (opts, raw_input(":".join(sorted(opts)) + " > ").split()) def list_components(param, regexp = True): res = [] num = 0 if not param: param = ".*" for c in self.components: if regexp and re.search(param, c["cname"]): res.append(c["cname"]) print num, c["cname"] num += 1 elif not regexp and param == c["cname"]: res.append(c["cname"]) break return res def get_component_data(name): #print self.components for c in self.components: if name == c["cname"]: return c print "Component %s not found!" % name return False def print_help(hdict): for i in iter(sorted(hdict.iteritems())): print i[0] + "\t" + i[1] def edit_loop(component): def update(key, val, data): d = val.split(":") if not len(d) == 2: print "Wrong param format! (ln lang:text)" else: lexists = -1 for i in data[key]: if i.split(":")[0] == d[0]: lexists = data[key].index(i) break if lexists > -1: data[key][lexists] = val else: data[key].append(val) return data data = get_component_data(component) while True: print "-" * (len(component) + 8) print "Editing " + component print "-" * (len(component) + 8) print "LocalName:" for i in data["clname"]: print " %s" %i print "Summary:" for i in data["csummary"]: print " %s" %i print "Description:" for i in data["cdesc"]: print " %s" %i print "Group:\n %s" % data["cgroup"] print "Maintainer name:\n %s" % data["mname"] print "Email:\n %s" % data["memail"] o, c = read_command("c") if not c[0] in o: continue if len(c) == 1: c.append("") if c[0] == "m": break elif c[0] == "h": print_help(ecommands) elif c[0] == "ln": data = update("clname", c[1], data) elif c[0] == "s": data = update("csummary", c[1], data) elif c[0] == "d": data = update("cdesc", c[1], data) elif c[0] == "mn": data["mname"] = c[1] elif c[0] == "me": data["memail"] = c[1] elif c[0] == "w": self.write_components() else: print"%s is not implemented yet" % c[0] def edit_component(param, l): try: int(param) edit_loop(l[int(param)]) except ValueError: l = list_components(param, regexp = False) if not len(l) == 1: print "Component %s not found" % param else: edit_loop(l[0]) while True: o, c = read_command("m") if len(c) == 1: c.append("") if not c[0] in o: continue elif c[0] == "q": break elif c[0] == "l": l = list_components(c[1]) elif c[0] == "c": edit_component(c[1], l) elif c[0] == "h": print_help(mcommands) else: print"%s is not implemented yet" % c[0] def check(self): cs = [] for root, dirs, files in os.walk(self.path): c = root.split(self.path)[1][1:].split("/") if "files" in c or "comar" in c: continue c = ".".join(c) component_xml = "%s/component.xml" % root pspec_xml = "%s/pspec.xml" % root actions_py = "%s/actions.py" % root if not os.path.isfile(component_xml) and not os.path.isfile(pspec_xml): if os.path.isfile(actions_py): print "WARNING: %s not exists" % pspec_xml else: is_src_repo = False for r, d, f in os.walk(root): if "pspec.xml" in f: is_src_repo = True break if is_src_repo and c: print "%s not exists. creating..." % component_xml write_file(component_xml, self.COMPONENT_XML % c) if os.path.isfile(component_xml) and c: cs.append(c) mcs = cs[:] csfile = read_file(self.components_xml) maintainer = False new_file = [] for line in csfile.split("\n"): new_file.append(line) if re.search(self.mbgn_ptrn, line): maintainer = True elif re.search(self.mend_ptrn, line): maintainer = False elif re.search(self.csend_ptrn, line): for m in mcs: new_file.insert(-1, self.EMPTY_COMPONENT % m) if not re.search(self.name_ptrn, line) or maintainer: continue cn = re.sub(self.name_ptrn, r"\1", line) if cn in mcs: mcs.pop(mcs.index(cn)) new_file = "\n".join(new_file) write_file(self.components_xml, new_file) if __name__ == "__main__": usage = "Usage: %prog [PATH]" parser = OptionParser(usage) parser.add_option("-c", "--check", action="store_true", dest="check", help="fix missing component.xml files and entries in components.xml") parser.add_option("-e", "--edit", action="store_true", dest="edit", help="edit components.xml") (options,args) = parser.parse_args() try: root = args[0] except IndexError: print "Using ./ as PATH" root = "./" if root.endswith("/"): root = root[:-1] cs = Components(root) if not os.path.isfile(cs.components_xml): print "%s not exists!" % cs.components_xml sys.exit(1) if not os.access(cs.components_xml, os.W_OK): print "Cannot write to %s" % cs.components_xml sys.exit(1) cs.read_components() if options.check: cs.check() if options.edit: cs.edit()