diff --git a/components.py b/components.py
new file mode 100755
index 0000000000..634942b72b
--- /dev/null
+++ b/components.py
@@ -0,0 +1,324 @@
+#!/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()
diff --git a/components.xml b/components.xml
index ecc653de38..782b821b6d 100755
--- a/components.xml
+++ b/components.xml
@@ -2354,5 +2354,27 @@
admins@pisilinux.org
+
+ desktop.kde.porting-aids
+ FIXME
+ FIXME
+ FIXME
+ FIXME
+
+ PisiLinux Community
+ admins@pisilinux.org
+
+
+
+ desktop.kde.phonon
+ FIXME
+ FIXME
+ FIXME
+ FIXME
+
+ PisiLinux Community
+ admins@pisilinux.org
+
+
diff --git a/desktop/kde/application/component.xml b/desktop/kde/application/component.xml
new file mode 100644
index 0000000000..21af6901d0
--- /dev/null
+++ b/desktop/kde/application/component.xml
@@ -0,0 +1,4 @@
+
+ desktop.kde.application
+
+
diff --git a/desktop/kde/graphics/component.xml b/desktop/kde/graphics/component.xml
new file mode 100644
index 0000000000..43a143702e
--- /dev/null
+++ b/desktop/kde/graphics/component.xml
@@ -0,0 +1,4 @@
+
+ desktop.kde.graphics
+
+
diff --git a/desktop/kde/sdk/component.xml b/desktop/kde/sdk/component.xml
new file mode 100644
index 0000000000..bbaec150e4
--- /dev/null
+++ b/desktop/kde/sdk/component.xml
@@ -0,0 +1,4 @@
+
+ desktop.kde.sdk
+
+
diff --git a/multimedia/converter/component.xml b/multimedia/converter/component.xml
new file mode 100644
index 0000000000..23206db999
--- /dev/null
+++ b/multimedia/converter/component.xml
@@ -0,0 +1,4 @@
+
+ multimedia.converter
+
+