Current Path : /usr/share/tools/ |
Current File : //usr/share/tools/reduce-xml |
#!/usr/bin/python # # Cuts out all the cruft for the udeb packages. import sys import os import string import re import traceback import getopt import xml.dom import xml.dom.minidom try: True except: True = 1 False = 0 config = { "filelist": [], "outfile": "-", "outtype": "device", "includebus": [], "excludebus": [], "classspec": [], "classversion": "", "modlistfile": "", "debug": False } toplevel_nodes = { "device": "device_list", "vendor": "vendor_list" } class UsageError(RuntimeError): pass def compare_versions(x, y): x_pieces = string.split(x, ".") y_pieces = string.split(y, ".") index = 0 while index < len(x_pieces) and index < len(y_pieces): if int(x_pieces[index]) != int(y_pieces[index]): return cmp(int(x_pieces[index]), int(y_pieces[index])) index = index + 1 return cmp(len(x_pieces), len(y_pieces)) def check_version(set_spec, version): if string.find(set_spec, "inf") != -1: pass include_left = (set_spec[0] == "[") include_right = (set_spec[-1] == "]") (left_version, right_version) = re.split(r',\s*', set_spec[1:-1]) if left_version == "inf": left_compare = -1 else: left_compare = compare_versions(left_version, version) if right_version == "inf": right_compare = 1 else: right_compare = compare_versions(version, right_version) if left_compare < 0 and right_compare < 0: return True if left_compare == 0 and include_left: return True if right_compare == 0 and include_right: return True return False def get_busclass(device_node, busclass_docs): if not device_node.attributes.has_key("busclass"): return None device_id = device_node.attributes["busclass"].value for doc in busclass_docs: for node in doc.documentElement.childNodes: if node.nodeType != xml.dom.Node.ELEMENT_NODE: continue id = node.attributes["id"].value if id == device_id: return node.attributes["name"].value return None def find_spec(spec, node): try: (spec_name, spec_rest) = string.split(spec, ":", 1) except: spec_name = spec spec_rest = None node_name = node.attributes["class"] if node_name is None: return False node_name = node_name.value if node_name == spec_name: if spec_rest is None: return True elif spec_rest[0] in string.digits: spec_version = spec_rest try: node_version_spec = node.attributes["version"] except KeyError: return True return check_version(node_version_spec.value, spec_version) else: for child_node in node.childNodes: if child_node.nodeType != xml.dom.Node.ELEMENT_NODE: continue if find_spec(spec_rest, child_node): return True return False else: return False def usage(f): f.write("need usage statement\n") def main(): global config global toplevel_nodes try: # Parse options (options, args) = getopt.getopt(sys.argv[1:], "di:o:", ["input-file=", "output-file=", "output-type=", "include-bus=", "exclude-bus=", "class-spec=", "module-list=", "debug"]) for option in options: if option[0] in ("-i", "--input-file"): config["filelist"].append(option[1]) elif option[0] in ("-o", "--output-file"): config["outfile"] = option[1] elif option[0] == "--output-type": config["outtype"] = option[1] elif option[0] == "--include-bus": config["includebus"].extend(string.split(option[1], ",")) elif option[0] == "--exclude-bus": config["excludebus"].extend(string.split(option[1], ",")) elif option[0] == "--class-spec": config["classspec"].append(option[1]) elif option[0] == "--module-list": config["modlistfile"] = option[1] elif option[0] in ("-d", "--debug"): config["debug"] = True else: raise UsageError, "invalid option: %s" % (option[0],) # Sanity-check options if len(config["filelist"]) == 0: raise UsageError, "need input busclass, vendor, and device files" if len(config["classspec"]) == 0: raise UsageError, "need at least one class specification" # Load module list information if present modlist = [] if config["modlistfile"] and os.path.exists(config["modlistfile"]): modlistfile = open(config["modlistfile"]) for line in modlistfile: modlist.append(string.strip(line)) modlistfile.close() # Load files bus_info = {} for fn in config["filelist"]: try: document = xml.dom.minidom.parse(fn) bus_id = document.documentElement.attributes["bus"].value except: sys.stderr.write("warning: couldn't parse %s, skipping.\n" % (fn,)) continue if not bus_info.has_key(bus_id): bus_info[bus_id] = { "busclass": [], "vendor": [], "device": [] } data_type = document.documentElement.tagName[:-5] try: bus_info[bus_id][data_type].append(document) except: sys.stderr.write("warning: invalid file %s, continuing.\n" % (fn,)) # Sanity-check file information if len(bus_info.keys()) != 1: raise RuntimeError, \ "one and only one bus type can be used at a time" bus_data = bus_info[bus_info.keys()[0]] for bus_type in ("busclass", "device"): if len(bus_data[bus_type]) == 0: raise RuntimeError, \ "required data for bus %s missing, aborting" \ % (bus_type,) # Create output device document outtype = config["outtype"] out = bus_data[outtype][0].implementation.createDocument(None, toplevel_nodes[outtype], None) out.documentElement.setAttribute("bus", bus_info.keys()[0]) # Iterate over the input device document, copying nodes we # don't want to strip to the output document. attr_list = [] for device_doc in bus_data["device"]: for device_node in device_doc.documentElement.childNodes: if device_node.nodeType != xml.dom.Node.ELEMENT_NODE: continue is_approved_busclass = True do_device_node = False module_in_list = False new_device_node = None busclass = get_busclass(device_node, bus_data["busclass"]) if busclass is None or \ busclass in config["excludebus"]: is_approved_busclass = False if len(config["includebus"]) > 0 and \ busclass not in config["includebus"]: is_approved_busclass = False for data_node in device_node.childNodes: if data_node.nodeType != xml.dom.Node.ELEMENT_NODE: continue do_data_node = False for spec in config["classspec"]: if find_spec(spec, data_node): npath = ["module", "name"] nnode = data_node.childNodes[0] while len(npath) > 0 and nnode is not None: while nnode is not None and \ nnode.nodeType != \ xml.dom.Node.ELEMENT_NODE: nnode = nnode.nextSibling if nnode is None: continue if nnode.getAttribute("class") == npath[0]: nnode = nnode.childNodes[0] npath.pop(0) else: nnode = nnode.nextSibling if nnode is not None: module_name = string.strip(nnode.nodeValue) if module_name in modlist: module_in_list = True break elif module_name not in ("ignore", "unknown"): do_data_node = True break if module_in_list or \ (do_data_node and is_approved_busclass): do_device_node = True if outtype == "device": if new_device_node is None: new_device_node = device_node.cloneNode(False) new_data_node = data_node.cloneNode(False) for mod_node in data_node.childNodes: if mod_node.nodeType != xml.dom.Node.ELEMENT_NODE: continue if mod_node.getAttribute("class") != "module": continue new_mod_node = mod_node.cloneNode(True) new_data_node.appendChild(new_mod_node) break new_device_node.appendChild(new_data_node) if do_device_node: if outtype == "device": out.documentElement.appendChild(new_device_node) else: attr_list.append(device_node.getAttribute(outtype)) # If we're reducing something besides the device list, create # that reduced document here. if outtype != "device": for doc in bus_data[outtype]: for node in doc.documentElement.childNodes: if node.nodeType != xml.dom.Node.ELEMENT_NODE: continue if node.getAttribute("id") in attr_list: new_node = node.cloneNode(True) out.documentElement.appendChild(new_node) # Write the output document if config["outfile"] == "-": out_file = sys.stdout else: out_file = open(config["outfile"], "w") out.writexml(out_file, encoding="UTF-8") except UsageError, e: sys.stderr.write(sys.argv[0] + ": " + str(e) + "\n") if config["debug"]: traceback.print_exc(None, sys.stderr) usage(sys.stderr) sys.exit(1) except Exception, e: sys.stderr.write(sys.argv[0] + ": " + str(e) + "\n") if config["debug"]: traceback.print_exc(None, sys.stderr) sys.exit(1) if __name__ == "__main__": main()