whoami7 - Manager
:
/
proc
/
self
/
root
/
usr
/
share
/
java-utils
/
Upload File:
files >> //proc/self/root/usr/share/java-utils/pom_editor.py
# from __future__ import print_function import re import shutil import sys import optparse import six import io from lxml import etree from os import path from textwrap import dedent from javapackages.common.exception import JavaPackagesToolsException # all macro fuctions that can be called from external world macros = {} def annotate(elements): begin_comment = etree.Comment(' begin of code added by maintainer ') end_comment = etree.Comment(' end of code added by maintainer ') if isinstance(elements, etree._Element): if elements.text and elements.text.strip(): begin_comment.tail = elements.text.strip() elements.text = '' elements[:0] = [begin_comment] elements.append(end_comment) return elements return [begin_comment] + elements + [end_comment] class PomException(JavaPackagesToolsException): pass class PomQueryNoMatch(PomException): pass class PomQueryAmbigous(PomException): pass class PomQueryInvalid(PomException): pass def MetaArtifact(specification, attributes=False, namespace=None, **defaults): parts = specification.split(':') class Artifact(object): def __init__(self, **values): self.values = values @classmethod def from_mvn_str(cls, string): values = {} for key, value in zip(parts, string.split(':')): if value: values[key] = value return cls(**values) def update(self, artifact): for key, value in six.iteritems(artifact.values): if key not in parts: raise KeyError(key + ' not defined') if value: self[key] = value def __getitem__(self, key): return self.values.get(key, '') def __setitem__(self, key, value): if key not in parts: raise KeyError(key + ' not defined') self.values[key] = value class NodeArtifact(Artifact): @classmethod def from_xml(cls, element): values = {} for part in parts: if namespace: subelements = element.xpath('ns:' + part, namespaces={'ns': namespace}) else: subelements = element.xpath(part) if subelements: values[part] = subelements[0].text.strip() return cls(**values) def get_xml(self, node='artifact', extra=''): xml = ['<{0}>'.format(node)] for key in parts: value = self.values.get(key, defaults.get(key, '')) if value: xml.append("<{0}>{1}</{0}>".format(key, value)) xml.append(extra) xml.append('</{0}>'.format(node)) return etree.fromstring('\n'.join(xml)) def merge_into_xml(self, element): for key in parts: value = self.values.get(key, defaults.get(key, '')) if value: child = element.xpath('ns:' + key, namespaces={'ns': namespace}) if child: if value == '-': element.remove(child[0]) else: child[0].text = value elif value != '-': child = element.makeelement(key) child.text = value element.append(child) def get_xpath_condition(self): expr = "normalize-space(pom:{0})='{1}'" conditions = [] for key in parts: value = self.values.get(key, '') if value and value != '*': conditions.append(expr.format(key, value)) return ' and '.join(conditions) if conditions else 'true()' class AttributeArtifact(Artifact): @classmethod def from_xml(cls, element): values = dict([(key, val) for key, val in six.iteritems(element.attrib) if key in parts]) return cls(**values) def get_xml(self, node='artifact', extra=''): xml = [] for key in parts: value = self.values.get(key, defaults.get(key, '')) if value: xml.append('{0}="{1}"'.format(key, value)) return etree.fromstring('<{0} {1}>{2}</{0}>' .format(node, ' '.join(xml), extra)) def merge_into_xml(self, element): for key in parts: value = self.values.get(key, defaults.get(key, '')) if value == '-': del element.attrib[key] elif value: element.attrib[key] = value def get_xpath_condition(self): expr = "@{0}='{1}'" conditions = [] for key in parts: value = self.values.get(key, '') if value and value != '*': conditions.append(expr.format(key, value)) return ' and '.join(conditions) if conditions else 'true()' return AttributeArtifact if attributes else NodeArtifact def find_xml(xmlpath): if path.isfile(xmlpath): return xmlpath if path.isdir(xmlpath): subxmlpath = path.join(xmlpath, 'pom.xml') if path.isfile(subxmlpath): return subxmlpath subxmlpath = path.join(xmlpath, 'ivy.xml') if path.isfile(subxmlpath): return subxmlpath raise PomException("Couldn't locate XML file using pattern '{0}'"\ .format(xmlpath)) def submodule_info(module_xml, module_path): module_xpath = '/pom:project/pom:modules/pom:module |'\ '/pom:project/pom:profile/pom:modules/pom:module' submodules = module_xml.xpath(module_xpath, namespaces=Pom.NSMAP) submodules = [node.text.strip() for node in submodules] if module_path: submod_paths = [path.join(path.dirname(module_path), submod) for submod in submodules] else: submod_paths = list(submodules) return submodules, submod_paths def find_xml_recursive(module_path): try: module_path = find_xml(module_path) module_xml = etree.parse(module_path) _, submod_paths = submodule_info(module_xml, module_path) found = [module_path] for submod_path in submod_paths: found += find_xml_recursive(submod_path) return found except IOError: raise PomException("Cannot read POM file '{0}'".format(module_path)) def get_indent(node): if node is None or not node.text: return '' text = node.text.split('\n')[-1] return re.sub(r'\S.*', '', text) def print_usage(function): print("Usage: %{name} {doc}".format(name=function.__name__, doc=function.__doc__), file=sys.stderr) def parse_args(function, args, nargs, last_xml_string=False): option_parser = optparse.OptionParser() option_parser.add_option('-r', '--recursive', action="store_true") option_parser.add_option('-f', '--force', action="store_true") options, arguments = option_parser.parse_args(list(args)) if len(arguments) < nargs: raise PomException('Too few arguments given to {0}'.format(function.__name__)) fnargs = arguments[:nargs] fnkwargs = {} poms = arguments[nargs:] if last_xml_string and poms: last = poms[-1] if '<' in last: del poms[-1] fnkwargs['xml_string'] = last if not poms: poms = ['.'] return options, fnargs, fnkwargs, poms class XmlFile(object): default_name = None NSMAP = {} XMLNS = '' def __init__(self, xmlpath): self.xmlpath = xmlpath encoding = etree.parse(xmlpath).docinfo.encoding with io.open(self.xmlpath, encoding=encoding) as raw_xml: raw_xml = raw_xml.read() raw_xml = self._preprocess_raw(raw_xml) self.xml_declaration = re.match(r'\<\?xml\s[^?]*\?\>', raw_xml) tmpfile = self.xmlpath + '.tmp' with io.open(tmpfile, 'w', encoding=encoding) as prepared: prepared.write(raw_xml) self.document = etree.parse(tmpfile) self.tab = get_indent(self.root) def _preprocess_raw(self, raw_xml): return raw_xml @property def root(self): return self.document.getroot() def write(self, filename): info = self.document.docinfo self.document.write(filename, encoding=info.encoding, xml_declaration=bool(self.xml_declaration)) with io.open(filename, 'ab') as xmlfile: xmlfile.write(b'\n') def patch(self, function, fnargs, fnkwargs): xmldir = path.dirname(self.xmlpath) xmlfile = path.basename(self.xmlpath) self.write(path.join(xmldir, xmlfile + '.tmp')) function(*fnargs, **fnkwargs) origfile = path.join(xmldir, xmlfile + '.orig') shutil.move(self.xmlpath, origfile) self.write(self.xmlpath) def inject_xml(self, parent, content): items = len(content) parent[:0] = content self.reformat(parent, parent[:items]) def replace_xml(self, replaced, content): parent = replaced.getparent() if not isinstance(replaced, etree._Element): parent.extend(content) if content.tag is not etree.Comment: parent.text = content.text return idx = parent.index(replaced) items = len(content) del parent[idx] for i, element in enumerate(content): parent.insert(idx + i, element) self.reformat(parent, parent[idx: idx + items]) def replace_xml_content(self, parent, content): if hasattr(parent, 'is_attribute'): if parent.is_attribute: parent.getparent().attrib[parent.attrname] = content.text return parent[:] = content parent.text = content.text self.reformat(parent, parent) def reformat(self, parent_node, elements): level = 0 element = parent_node while element is not None: level += 1 element = element.getparent() base = self.tab * level def prettify_node(node, parent, indent): if parent[0] == node: text = parent.text or '' parent.text = text.strip() + '\n' + indent tail = node.tail or '' if parent[-1] == node: node.tail = tail.strip() + '\n' + indent[:len(indent) - len(self.tab)] else: node.tail = tail.strip() + '\n' + indent for child in node: prettify_node(child, node, indent + self.tab) for element in elements: prettify_node(element, parent_node, base) def xpath_query_element(self, query): query_result = self.xpath_query(query) if len(query_result) > 1: raise PomQueryAmbigous("XPath query '{0}' matched more than one nodes."\ .format(query)) return query_result[0] def xpath_query(self, query, boolean=False): if not query.startswith('/'): query = '//' + query if boolean: query = 'boolean({0})'.format(query) try: nsmap = dict(self.NSMAP) nsmap.update(self.root.nsmap) if None in nsmap: nsmap['default'] = nsmap[None] del nsmap[None] query_result = self.root.xpath(query, namespaces=nsmap) except etree.XPathEvalError as error: raise PomQueryInvalid("XPath query '{0}': {1}.".format(query, error)) if not boolean: if len(query_result) == 0: raise PomQueryNoMatch(dedent("""\ XPath query '{0}' didn't match any node. (Did you forget to specify 'pom:' namespace?)""").format(query)) for i, element in enumerate(query_result): if hasattr(element, 'is_attribute') and element.is_attribute: if not hasattr(element, 'attrname'): element.attrname = self.root.xpath('name({q}[{i1}])'.format(q=query, i1=i + 1), namespaces=nsmap) return query_result def subtree_from_string(self, xml_string): document = "<root {ns}>{0}</root>".format(xml_string, ns=self.XMLNS) try: tree = etree.fromstring(document) except etree.XMLSyntaxError as error: raise PomException("Syntax error in injected XML: {0}.".format(error)) return tree def make_path(self, node, elements): if elements: elem = elements[0] children = node.xpath(elem, namespaces=self.NSMAP) if not children: name = elements[0] for ns, url in six.iteritems(self.NSMAP): ns_token = ns + ':' url_token = '{' + url + '}' name = name.replace(ns_token, url_token) child = etree.Element(name) node.insert(0, child) node.insert(0, etree.Comment(" section added by maintainer ")) self.reformat(node, node[:2]) else: child = children[0] return self.make_path(child, elements[1:]) return node def inject_artifact(self, where, node_name, artifact, aux_content=''): path_parts = [part for part in where.split('/') if part] parent = self.make_path(self.root, path_parts) content = annotate([artifact.get_xml(node_name, aux_content)]) self.inject_xml(parent, content) class Pom(XmlFile): default_name = 'pom.xml' NSMAP = {'pom': 'http://maven.apache.org/POM/4.0.0', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'} NS = '{' + NSMAP['pom'] + '}' XMLNS = ('xmlns="http://maven.apache.org/POM/4.0.0" ' 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' 'xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 ' 'http://maven.apache.org/xsd/maven-4.0.0.xsd"') DEPENDENCY_NODE = 'pom:dependency' DEPENDENCIES_NODE = 'pom:dependencies' def __init__(self, pompath): super(Pom, self).__init__(pompath) def _preprocess_raw(self, raw_xml): return re.sub(r'\<\s*project\s*\>', u'<project {ns}>'.format(ns=self.XMLNS), raw_xml) @classmethod def create_artifact(cls, *args, **kwargs): plugin = kwargs.get('plugin', False) if 'plugin' in kwargs: del kwargs['plugin'] if plugin: pom_plugin_spec = 'groupId:artifactId:version' ArtifactClass = MetaArtifact(pom_plugin_spec, namespace=cls.NSMAP['pom'], version='any', groupId='org.apache.maven.plugins') else: pom_dependency_spec = 'groupId:artifactId:version:scope:classifier' ArtifactClass = MetaArtifact(pom_dependency_spec, namespace=cls.NSMAP['pom'], version='any') return ArtifactClass(*args, **kwargs) class Ivy(XmlFile): DEPENDENCY_NODE = 'dependency' DEPENDENCIES_NODE = 'dependencies' def __init__(self, pompath): super(Ivy, self).__init__(pompath) @classmethod def create_artifact(cls, *args, **kwargs): if 'plugin' in kwargs: del kwargs['plugin'] ivy_dependency_spec = 'org:name:rev:conf:transitive' IvyDependency = MetaArtifact(ivy_dependency_spec, attributes=True) return IvyDependency(*args, **kwargs) def create_xml_object(filepath): tree = etree.parse(filepath) root = tree.getroot() pom_detect = '/pom:project/pom:modelVersion|/project/modelVersion' if root.xpath(pom_detect, namespaces=Pom.NSMAP): return Pom(filepath) if root.tag == 'ivy-module': return Ivy(filepath) return XmlFile(filepath) def macro(types=(XmlFile,), nargs=1, last_xml_string=False): def decorator(function): def decorated(*args): try: xmlpath = None options, fnargs, fnkwargs, xmls = parse_args( function, args, nargs, last_xml_string ) stored_exception = None for xmlspec in xmls: if options.recursive: xmlpaths = find_xml_recursive(xmlspec) else: xmlpaths = [find_xml(xmlspec)] matches = 0 for xmlpath in xmlpaths: try: xml = create_xml_object(xmlpath) if not any([isinstance(xml, allowed) for allowed in types]): raise PomException('Operation not supported on ' 'given file type.') fnkwargs['pom'] = xml xml.patch(function, fnargs, fnkwargs) matches += 1 except PomQueryNoMatch as exception: stored_exception = exception if matches == 0 and not options.force: # pylint: disable=E0702 raise stored_exception except (PomException, etree.XMLSyntaxError, IOError) as exception: if xmlpath: print("Error in processing {0}".format(xmlpath), file=sys.stderr) print(exception, file=sys.stderr) print_usage(function) sys.exit(3) macros[function.__name__] = decorated return decorated return decorator def disable_module(pom, module): xpath = "//pom:module[normalize-space(text())='{0}']".format(module) elements = pom.xpath_query(xpath) for element in elements: pom.replace_xml(element, etree.Comment(" module removed by maintainer: {0} ".format(module))) @macro(nargs=2) def pom_xpath_inject(where, xml_string, pom=None): """<XPath> <XML code> [POM location]""" for element in pom.xpath_query(where): pom.inject_xml(element, annotate(pom.subtree_from_string(xml_string))) @macro(nargs=2) def pom_xpath_replace(where, xml_string, pom=None): """<XPath> <XML code> [POM location]""" for element in pom.xpath_query(where): pom.replace_xml(element, annotate(pom.subtree_from_string(xml_string))) @macro(nargs=1) def pom_xpath_remove(where, pom=None): """<XPath> [POM location]""" for element in pom.xpath_query(where): if hasattr(element, 'is_attribute') and element.is_attribute: del element.getparent().attrib[element.attrname] else: pom.replace_xml(element, etree.Comment(" element removed by maintainer: {0} ".format(where))) @macro(nargs=2) def pom_xpath_set(where, content, pom=None): """<XPath> <new contents> [POM location]""" for element in pom.xpath_query(where): pom.replace_xml_content(element, pom.subtree_from_string(content)) @macro(types=(Pom,), nargs=1) def pom_xpath_disable(when, pom=None): """<XPath> [POM location]""" to_disable = [] def disable_recursive(pom): if pom.xpath_query(when, boolean=True): return True for submodule, submod_path in zip(*submodule_info(pom.root, pom.xmlpath)): realpath = find_xml(submod_path) subpom = Pom(realpath) if disable_recursive(subpom): to_disable.append((pom, submodule)) if disable_recursive(pom): raise PomException("Main POM satisfies the condition") if not to_disable: raise PomQueryNoMatch("Condition didn't match any module") for pom, module in to_disable: pom.patch(disable_module, [pom, module], {}) @macro(types=(Pom, Ivy), nargs=1) def pom_remove_dep(dep, pom=None): """[groupId]:[artifactId] [POM location]""" try: artifact = pom.create_artifact().from_mvn_str(dep) xpath = "//{0}[{1}]".format(pom.DEPENDENCY_NODE, artifact.get_xpath_condition()) elements = pom.xpath_query(xpath) for element in elements: pom.replace_xml(element, etree.Comment(" dependency removed by maintainer: {0} ".format(dep))) except PomQueryNoMatch: raise PomQueryNoMatch("Dependency '{0}' not found.".format(dep)) @macro(types=(Pom,), nargs=1) def pom_remove_plugin(plugin, pom=None): """[groupId]:[artifactId] [POM location]""" try: artifact = pom.create_artifact(plugin=True).from_mvn_str(plugin) xpath = "//pom:plugin[{0}]".format(artifact.get_xpath_condition()) elements = pom.xpath_query(xpath) for element in elements: pom.replace_xml(element, etree.Comment(" plugin removed by maintainer: {0} ".format(plugin))) except PomQueryNoMatch: raise PomQueryNoMatch("Plugin '{0}' not found.".format(plugin)) @macro(types=(Pom,), nargs=1) def pom_disable_module(module, pom=None): """<module name> [POM location]""" try: disable_module(pom, module) except PomQueryNoMatch: raise PomQueryNoMatch("Module '{0}' not found.".format(module)) @macro(types=(Pom,), nargs=1) def pom_add_parent(parent, pom=None): """groupId:artifactId[:version] [POM location]""" if pom.xpath_query('/pom:parent', boolean=True): raise PomException("POM already has a parent.") artifact = pom.create_artifact().from_mvn_str(parent) pom.inject_artifact('', 'parent', artifact) @macro(types=(Pom,), nargs=0) def pom_remove_parent(pom=None): """[POM location]""" try: pom.replace_xml(pom.xpath_query_element("/pom:project/pom:parent"), etree.Comment(" parent POM reference removed by maintainer ")) except PomQueryNoMatch: raise PomQueryNoMatch("POM doesn't specify parent.") @macro(types=(Pom,), nargs=1) def pom_set_parent(parent, pom=None): """groupId:artifactId[:version] [POM location]""" try: artifact = pom.create_artifact().from_mvn_str(parent) element = pom.xpath_query_element("/pom:project/pom:parent") pom.replace_xml_content(element, artifact.get_xml()) except PomQueryNoMatch: raise PomQueryNoMatch("POM doesn't specify parent.") @macro(types=(Pom, Ivy), nargs=1, last_xml_string=True) def pom_add_dep(dep, pom=None, xml_string=''): """groupId:artifactId[:version[:scope]] [POM location] [extra XML]""" artifact = pom.create_artifact().from_mvn_str(dep) pom.inject_artifact(pom.DEPENDENCIES_NODE, 'dependency', artifact, xml_string) @macro(types=(Pom,), nargs=1, last_xml_string=True) def pom_add_dep_mgmt(dep, pom=None, xml_string=''): """groupId:artifactId[:version[:scope]] [POM location] [extra XML]""" artifact = pom.create_artifact().from_mvn_str(dep) pom.inject_artifact('pom:dependencyManagement/pom:dependencies', 'dependency', artifact, xml_string) @macro(types=(Pom,), nargs=1, last_xml_string=True) def pom_add_plugin(plugin, pom=None, xml_string=''): """groupId:artifactId[:version] [POM location] [extra XML]""" artifact = pom.create_artifact(plugin=True).from_mvn_str(plugin) pom.inject_artifact('pom:build/pom:plugins', 'plugin', artifact, xml_string) @macro(nargs=2, last_xml_string=True) def pom_change_dep(old, new, pom=None, xml_string=''): """groupId:artifactId[:version] groupId:artifactId[:version[:scope]] [POM location] [extra XML]""" try: old_artifact = pom.create_artifact().from_mvn_str(old) xpath = "//{0}[{1}]".format(pom.DEPENDENCY_NODE, old_artifact.get_xpath_condition()) elements = pom.xpath_query(xpath) for element in elements: new_artifact = pom.create_artifact().from_xml(element) new_artifact.update(pom.create_artifact().from_mvn_str(new)) new_artifact.merge_into_xml(element) except PomQueryNoMatch: raise PomQueryNoMatch("Dependency '{0}' not found.".format(old)) if __name__ == '__main__': if len(sys.argv) <= 1: print("Usage:\n\t{0} command {{arguments}}".format(sys.argv[0]), file=sys.stderr) sys.exit(1) try: macros[sys.argv[1]](*sys.argv[2:]) except JavaPackagesToolsException as e: sys.exit(e)
Copyright ©2021 || Defacer Indonesia