GIF89a;
Direktori : /lib/python2.7/site-packages/javapackages/ |
Current File : //lib/python2.7/site-packages/javapackages/xmvn_config.py |
#!/usr/bin/python # Copyright (c) 2013, Red Hat, Inc # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the # distribution. # 3. Neither the name of Red Hat nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Authors: Stanislav Ochotnicky <sochotnicky@redhat.com> import codecs import os import errno import re from StringIO import StringIO import xml.dom.minidom import lxml import lxml.etree as ET from lxml.etree import ElementTree, Element, SubElement from javapackages.artifact import ArtifactValidationException class XMvnConfigException(Exception): pass class XMvnConfig(object): """ Class for modifying XMvn configuration """ INDEX_PATH = os.path.join(".xmvn", "javapackages-rule-index") CONFIG_DIR = os.path.join(".xmvn", "config.d") XMLNS = "http://fedorahosted.org/xmvn/CONFIG/0.6.0" def __init__(self): self.templateXML ="""<?xml version='1.0' encoding='utf-8'?> <configuration xmlns="http://fedorahosted.org/xmvn/CONFIG/0.6.0"> {content} </configuration> """ try: os.makedirs(XMvnConfig.CONFIG_DIR, 0755) except OSError: # If directory already exists then it's OK. If it doesn't # then creating the index file below will fail anyways. pass try: with open(XMvnConfig.INDEX_PATH) as index: self.index = int(index.read()) + 1 except IOError as e: if e.errno == errno.ENOENT: self.index = 1 else: raise e def __write_index(self): with open(XMvnConfig.INDEX_PATH, 'w') as index: index.write(str(self.index)) self.index = self.index + 1 def __get_current_config(self): fname = 'javapackages-config-{index:05d}.xml'.format(index=self.index) return os.path.join(XMvnConfig.CONFIG_DIR, fname) def __init_xml(self, content=""): self.__write_index() xmlbuf = StringIO() xmlbuf.write(self.templateXML.format(content=content)) root = ET.fromstring(xmlbuf.getvalue()) root.append(ET.Comment("XMvn configuration file generated by " "javapackages.xmvn_config (part of " "javapackages-tools)")) return root def __prettify_element(self, elem): xmlbuf = StringIO() et = ElementTree() et._setroot(elem) et.write(xmlbuf, xml_declaration=True, encoding = 'utf-8', method = "xml", pretty_print=True) return xmlbuf.getvalue() def __write_xml(self, path, root): xmlstr = self.__prettify_element(root) with codecs.open(path, 'w+', "utf-8") as fout: fout.write(xmlstr) def __add_config(self, level1, level2, level3=None, content=None): if not content: raise Exception("Provide content as keyword argument") confpath = self.__get_current_config() root = self.__init_xml() level1 = SubElement(root, level1) level2 = SubElement(level1, level2) cont_level = level2 if level3: cont_level = SubElement(level2, level3) if isinstance(content, basestring): cont_level.text = content elif isinstance(content, list): for elem in content: cont_level.append(elem) else: cont_level.append(content) self.__write_xml(confpath, root) def __count_backreferences(self, s): """ Return maximum number of backreference used in string s """ backref_re = re.compile('@(\d+)') backref_nos = [int(x) for x in backref_re.findall(s)] if backref_nos: return max((int(x) for x in backref_re.findall(s))) return 0 def __count_wildcard_groups(self, s): """ Return number of wildcard groups used in string s """ left = s.count('{') right = s.count('}') if left != right: raise Exception("Number of opening and closing " "parenthesis for groups of wildcard " "matching is different.") return left def add_aliases(self, artifact, aliases): """ Adds alias artifacts for given main artifact artifact -- main Artifact for which aliases are being provided aliases -- list of alternate Artifact representations """ artifact.validate(allow_backref=False) wild_groups = self.__count_wildcard_groups(artifact.get_rpm_str()) main = artifact.get_xml_element(root="artifactGlob") elems = [main] aelem = Element("aliases") for alias in aliases: alias.validate(allow_empty=False, allow_wildcards=False) backrefs = self.__count_backreferences(alias.get_rpm_str()) if backrefs > wild_groups: raise ArtifactValidationException("Number of backrefenreces " "is higher than wildcard " "groups.") aelem.append(alias.get_xml_element(root="alias")) elems.append(aelem) self.__add_config("artifactManagement", "rule", content=elems) def add_compat_versions(self, artifact, versions): """ Change where on filesystem given artifact is installed artifact -- Artifact to be modified versions -- list of compat versions for given artifact """ artifact.validate(allow_backref=False) wild_groups = self.__count_wildcard_groups(artifact.get_rpm_str(artifact.version)) main = artifact.get_xml_element(root="artifactGlob") elems = [main] velem = Element("versions") for version in versions: backrefs = self.__count_backreferences(version) if backrefs > wild_groups: raise ArtifactValidationException("Number of backrefenreces " "is higher than wildcard " "groups.") ve = SubElement(velem, "version") ve.text = version elems.append(velem) self.__add_config("artifactManagement", "rule", content=elems) def add_file_mapping(self, artifact, paths): """ Change where on filesystem given artifact is installed artifact -- Artifact to be modified paths -- list of paths for given artifact """ artifact.validate(allow_backref=False) wild_groups = self.__count_wildcard_groups(artifact.get_rpm_str()) main = artifact.get_xml_element(root="artifactGlob") elems = [main] felem = Element("files") if not [path for path in paths if not os.path.isabs(path)]: raise XMvnConfigException("At least one path must be relative") for path in paths: backrefs = self.__count_backreferences(path) if backrefs > wild_groups: raise ArtifactValidationException("Number of backrefenreces " "is higher than wildcard " "groups.") pe = SubElement(felem, "file") pe.text = path elems.append(felem) self.__add_config("artifactManagement", "rule", content=elems) def add_package_mapping(self, artifact, package, optional=False): """ Change which package given artifact belongs to artifact -- Artifact to be modified package -- subpackage name where artifact belongs """ artifact.validate(allow_backref=False) wild_groups = self.__count_wildcard_groups(artifact.get_rpm_str()) main = artifact.get_xml_element(root="artifactGlob") backrefs = self.__count_backreferences(package) if backrefs > wild_groups: raise ArtifactValidationException("Number of backrefenreces " "is higher than wildcard " "groups.") elems = [main] if optional: opt = Element("optional") opt.text = "true" elems.append(opt) target = Element("targetPackage") target.text = package elems.append(target) self.__add_config("artifactManagement", "rule", content=elems) def add_custom_option(self, optionstr, content): """ Add custom configuration option optionstr -- XPath-like expression for specifying XMvn configuration option location with '/' used as delimiter example: buildSettings/compilerSource content -- XML content to be added to specified node. Can be just text, XML node or multiple nodes. examples: someText <someNode>someText</someNode><someOtherNode/> """ node_names = optionstr.split("/") confpath = self.__get_current_config() root = self.__init_xml() par = root for node in node_names: par = SubElement(par, node) try: #wrap content into something to allow text content inserted = "<root>{0}</root>".format(content); contentRoot = ET.fromstring(inserted); par.text = contentRoot.text for element in contentRoot: par.append(element) except lxml.etree.XMLSyntaxError: raise Exception("content is not valid content for XML node") self.__write_xml(confpath, root)