#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Model to parse manifest files.""" from lxml import etree from lxml import objectify class MavenPom: """Model for Maven POM (Project Object Model).""" def __init__(self, document=None): """Initialize constructor for MavenPom class. :document: Parse the content of the file. :returns: None """ if not document: raise ValueError("No content is provided for parsing") self.document = document.strip() if not isinstance(self.document, (bytes, bytearray)): self.document = self.document.encode() self.root = objectify.fromstring(self.document) # create a dependencies element if doesn't exist if getattr(self.root, 'dependencies', None) is None: _prev = getattr(self.root, 'dependencyManagement', None)\ or getattr(self.root, 'properties', None)\ or getattr(self.root, 'name', None) if _prev is not None: _prev.addnext(objectify.Element('dependencies')) else: self.root.dependencies = objectify.ObjectifiedElement() self.root = self._reload(self.root) self.dependency_set = set([self.Dependency(d) for d in getattr( self.root.dependencies, 'dependency', [])]) def __getitem__(self, key): """Return the value for attr key.""" attr = getattr(self.root, key, None) objectify.deannotate(self.root) return attr def __setitem__(self, key, value): """Set value for attr key.""" _prev = getattr(self.root, 'modelVersion', None) if key in ('groupId', 'artifactId', 'name', 'version', 'packaging') and _prev is not None: # add these tags just after modelVersion tag. element = etree.Element(key) element.text = value _prev.addnext(element) else: setattr(self.root, key, value) objectify.deannotate(self.root) self._reload(self.root) def add_element(self, data={}, parent=None, next_to=None): """Add element to POM. data: dict parent: etree.Element or string return: None """ _prev = None if next_to is not None: if isinstance(next_to, (str, bytes)): _prev = getattr(self.root, next_to, None) else: _prev = next_to if isinstance(parent, (str, bytes)): if _prev is not None: parent = etree.Element(parent) _prev.addnext(parent) else: parent = etree.SubElement(self.root, parent) if isinstance(data, dict): for key, value in data.items(): self.add_element(value, etree.SubElement(parent, key)) elif isinstance(data, (tuple, list)): for value in data: self.add_element(value, parent) elif isinstance(data, (bytes, bytearray)): parent._setText(data.decode()) else: parent._setText(data) def add_dependency(self, dependency): """Add dependency to POM. dependency: dict return: None """ self.dependency_set.add(self.Dependency(dependency)) def add_dependencies(self, dependencies): """Add dependency to POM. dependencies: list return: None """ self.dependency_set.update({self.Dependency(dep) for dep in dependencies}) def remove_dependency(self, dependency): """Remove dependency to POM. dependency: dict return: None """ self.dependency_set.remove(self.Dependency(dependency)) def __contains__(self, dependency): """Check for dependency exists or not. dependency: dict return: bool """ return self.Dependency(dependency) in self.dependency_set def get_dependencies(self): """Return list of all the dependencies. return: generator """ for dep in self.dependency_set: yield dep def _commit(self): """Commit the changes to the XML root object.""" for dep in self.dependency_set: self.root.dependencies.append(MavenPom.to_objectify(dep)) self.root = self._reload(self.root) @staticmethod def tostring(obj, decoding=False): """Convert the xml object into string. :returns: String """ if getattr(obj, '_commit', None) is not None: obj._commit() objectify.deannotate(obj.root, xsi_nil=True, pytype=False, xsi=False, cleanup_namespaces=True) _str = etree.tostring(obj.root, pretty_print=True) if decoding: return _str.decode() return _str @staticmethod def to_objectify(obj): """Convert the object into ObjectifiedElement. :returns: ObjectifiedElement """ return obj.root @staticmethod def _reload(obj): obj = objectify.fromstring(etree.tostring(obj)) objectify.deannotate(obj, xsi_nil=True, cleanup_namespaces=True) return obj class Dependency: """Dependency class of outer class MavenPom.""" def __init__(self, dependency=None): """Initialize constructor for Dependency class. :returns: None """ self.Exclusion = MavenPom.Exclusion if dependency is not None: if not isinstance(dependency, objectify.ObjectifiedElement): self.root = objectify.Element('dependency') else: self.root = dependency for k, v in dependency.items(): if k == 'exclusions' and len(v) > 0: self.root.exclusions = objectify.ObjectifiedElement() for excl in v: self.root.exclusions.append( MavenPom.to_objectify(self.Exclusion(excl))) else: setattr(self.root, k, v) def __repr__(self): """Representation of an Dependency object in string.""" return "groupId: {}\nartifactId: {}"\ .format(self.root.groupId, self.root.artifactId) def __eq__(self, other): """Check equality of dependency object. other: Dependency Return: boolean """ return (self.root.groupId, self.root.artifactId) ==\ (other.root.groupId, other.root.artifactId) def __ne__(self, other): """Check non-equality of Dependency object. other: Dependency Return: boolean """ return not self.__eq__(other) def __getitem__(self, key): """Return the value for attr key.""" attr = getattr(self.root, key, None) objectify.deannotate(self.root) return attr def __setitem__(self, key, value): """Set value for attr key.""" attr = setattr(self.root, key, value) objectify.deannotate(self.root) return attr def __hash__(self): """Return hash for String representation of an Dependency object.""" return hash(self.__repr__()) class Exclusion: """Exclusion class of outer class MavenPom.""" def __init__(self, exclusion=None): """Initialize constructor for Exclusion class. :returns: None """ if exclusion is not None: if not isinstance(exclusion, objectify.ObjectifiedElement): self.root = objectify.Element('exclusion') else: self.root = exclusion for k, v in exclusion.items(): setattr(self.root, k, v) def __eq__(self, other): """Check equality of Exclusion object. other: Exclusion Return: boolean """ return (self.root.groupId, self.root.artifactId) ==\ (other.root.groupId, other.root.artifactId) def __ne__(self, other): """Check non-equality of Exclusion object. other: Exclusion Return: boolean """ return not self.__eq__(other) def __getitem__(self, key): """Return the value for attr key.""" return getattr(self.root, key, None) def __setitem__(self, key, value): """Set value for attr key.""" return setattr(self.root, key, value) class Properties: """Properties class of outer class MavenPom.""" pass class Plugin: """Plugin class of outer class MavenPom.""" pass class PypiRequirements: """Model for pip requirements.txt.""" def __init__(self): """Initialize constructor for PypiRequirements class. :returns: None """ raise NotImplementedError class NpmPackage: """Model for NPM package.json.""" def __init__(self): """Initialize constructor for NpmPackage class. :returns: None """ raise NotImplementedError