diff options
Diffstat (limited to 'pym/gentoolkit/metadata.py')
-rw-r--r-- | pym/gentoolkit/metadata.py | 454 |
1 files changed, 228 insertions, 226 deletions
diff --git a/pym/gentoolkit/metadata.py b/pym/gentoolkit/metadata.py index 9dc9619..2678611 100644 --- a/pym/gentoolkit/metadata.py +++ b/pym/gentoolkit/metadata.py @@ -31,8 +31,8 @@ 'Thomas Mills Hinkle' """ -__all__ = ('MetaData',) -__docformat__ = 'epytext' +__all__ = ("MetaData",) +__docformat__ = "epytext" # ======= # Imports @@ -48,260 +48,262 @@ from portage import settings # Classes # ======= + class _Maintainer: - """An object for representing one maintainer. - - @type email: str or None - @ivar email: Maintainer's email address. Used for both Gentoo and upstream. - @type name: str or None - @ivar name: Maintainer's name. Used for both Gentoo and upstream. - @type description: str or None - @ivar description: Description of what a maintainer does. Gentoo only. - @type restrict: str or None - @ivar restrict: e.g. >=portage-2.2 means only maintains versions - of Portage greater than 2.2. Should be DEPEND string with < and > - converted to < and > respectively. - @type status: str or None - @ivar status: If set, either 'active' or 'inactive'. Upstream only. - """ - - def __init__(self, node): - self.email = None - self.name = None - self.description = None - self.restrict = node.get('restrict') - self.status = node.get('status') - for attr in node.iter(): - setattr(self, attr.tag, attr.text) - - def __repr__(self): - return "<%s %r>" % (self.__class__.__name__, self.email) + """An object for representing one maintainer. + + @type email: str or None + @ivar email: Maintainer's email address. Used for both Gentoo and upstream. + @type name: str or None + @ivar name: Maintainer's name. Used for both Gentoo and upstream. + @type description: str or None + @ivar description: Description of what a maintainer does. Gentoo only. + @type restrict: str or None + @ivar restrict: e.g. >=portage-2.2 means only maintains versions + of Portage greater than 2.2. Should be DEPEND string with < and > + converted to < and > respectively. + @type status: str or None + @ivar status: If set, either 'active' or 'inactive'. Upstream only. + """ + + def __init__(self, node): + self.email = None + self.name = None + self.description = None + self.restrict = node.get("restrict") + self.status = node.get("status") + for attr in node.iter(): + setattr(self, attr.tag, attr.text) + + def __repr__(self): + return "<%s %r>" % (self.__class__.__name__, self.email) class _Useflag: - """An object for representing one USE flag. - - @todo: Is there any way to have a keyword option to leave in - <pkg> and <cat> for later processing? - @type name: str or None - @ivar name: USE flag - @type restrict: str or None - @ivar restrict: e.g. >=portage-2.2 means flag is only avaiable in - versions greater than 2.2 - @type description: str - @ivar description: description of the USE flag - """ - - def __init__(self, node): - self.name = node.get('name') - self.restrict = node.get('restrict') - _desc = '' - if node.text: - _desc = node.text - for child in node.iter(): - # prevent duplicate text - if child.text and child.text not in _desc: - _desc += child.text - if child.tail and not child.tail in _desc: - _desc += child.tail - # This takes care of tabs and newlines left from the file - self.description = re.sub(r'\s+', ' ', _desc) - - def __repr__(self): - return "<%s %r>" % (self.__class__.__name__, self.name) + """An object for representing one USE flag. + + @todo: Is there any way to have a keyword option to leave in + <pkg> and <cat> for later processing? + @type name: str or None + @ivar name: USE flag + @type restrict: str or None + @ivar restrict: e.g. >=portage-2.2 means flag is only avaiable in + versions greater than 2.2 + @type description: str + @ivar description: description of the USE flag + """ + + def __init__(self, node): + self.name = node.get("name") + self.restrict = node.get("restrict") + _desc = "" + if node.text: + _desc = node.text + for child in node.iter(): + # prevent duplicate text + if child.text and child.text not in _desc: + _desc += child.text + if child.tail and not child.tail in _desc: + _desc += child.tail + # This takes care of tabs and newlines left from the file + self.description = re.sub(r"\s+", " ", _desc) + + def __repr__(self): + return "<%s %r>" % (self.__class__.__name__, self.name) class _Upstream: - """An object for representing one package's upstream. - - @type maintainers: list - @ivar maintainers: L{_Maintainer} objects for each upstream maintainer - @type changelogs: list - @ivar changelogs: URLs to upstream's ChangeLog file in str format - @type docs: list - @ivar docs: Sequence of tuples containing URLs to upstream documentation - in the first slot and 'lang' attribute in the second, e.g., - [('http.../docs/en/tut.html', None), ('http.../doc/fr/tut.html', 'fr')] - @type bugtrackers: list - @ivar bugtrackers: URLs to upstream's bugtracker. May also contain an email - address if prepended with 'mailto:' - @type remoteids: list - @ivar remoteids: Sequence of tuples containing the project's hosting site - name in the first slot and the project's ID name or number for that - site in the second, e.g., [('sourceforge', 'systemrescuecd')] - """ - - def __init__(self, node): - self.node = node - self.maintainers = self.upstream_maintainers() - self.changelogs = self.upstream_changelogs() - self.docs = self.upstream_documentation() - self.bugtrackers = self.upstream_bugtrackers() - self.remoteids = self.upstream_remoteids() - - def __repr__(self): - return "<%s %r>" % (self.__class__.__name__, self.__dict__) - - def upstream_bugtrackers(self): - """Retrieve upstream bugtracker location from xml node.""" - return [e.text for e in self.node.findall('bugs-to')] - - def upstream_changelogs(self): - """Retrieve upstream changelog location from xml node.""" - return [e.text for e in self.node.findall('changelog')] - - def upstream_documentation(self): - """Retrieve upstream documentation location from xml node.""" - result = [] - for elem in self.node.findall('doc'): - lang = elem.get('lang') - result.append((elem.text, lang)) - return result - - def upstream_maintainers(self): - """Retrieve upstream maintainer information from xml node.""" - return [_Maintainer(m) for m in self.node.findall('maintainer')] - - def upstream_remoteids(self): - """Retrieve upstream remote ID from xml node.""" - return [(e.text, e.get('type')) for e in self.node.findall('remote-id')] + """An object for representing one package's upstream. + + @type maintainers: list + @ivar maintainers: L{_Maintainer} objects for each upstream maintainer + @type changelogs: list + @ivar changelogs: URLs to upstream's ChangeLog file in str format + @type docs: list + @ivar docs: Sequence of tuples containing URLs to upstream documentation + in the first slot and 'lang' attribute in the second, e.g., + [('http.../docs/en/tut.html', None), ('http.../doc/fr/tut.html', 'fr')] + @type bugtrackers: list + @ivar bugtrackers: URLs to upstream's bugtracker. May also contain an email + address if prepended with 'mailto:' + @type remoteids: list + @ivar remoteids: Sequence of tuples containing the project's hosting site + name in the first slot and the project's ID name or number for that + site in the second, e.g., [('sourceforge', 'systemrescuecd')] + """ + + def __init__(self, node): + self.node = node + self.maintainers = self.upstream_maintainers() + self.changelogs = self.upstream_changelogs() + self.docs = self.upstream_documentation() + self.bugtrackers = self.upstream_bugtrackers() + self.remoteids = self.upstream_remoteids() + + def __repr__(self): + return "<%s %r>" % (self.__class__.__name__, self.__dict__) + + def upstream_bugtrackers(self): + """Retrieve upstream bugtracker location from xml node.""" + return [e.text for e in self.node.findall("bugs-to")] + + def upstream_changelogs(self): + """Retrieve upstream changelog location from xml node.""" + return [e.text for e in self.node.findall("changelog")] + + def upstream_documentation(self): + """Retrieve upstream documentation location from xml node.""" + result = [] + for elem in self.node.findall("doc"): + lang = elem.get("lang") + result.append((elem.text, lang)) + return result + + def upstream_maintainers(self): + """Retrieve upstream maintainer information from xml node.""" + return [_Maintainer(m) for m in self.node.findall("maintainer")] + + def upstream_remoteids(self): + """Retrieve upstream remote ID from xml node.""" + return [(e.text, e.get("type")) for e in self.node.findall("remote-id")] class MetaData: - """Access metadata.xml""" - - def __init__(self, metadata_path): - """Parse a valid metadata.xml file. - - @type metadata_path: str - @param metadata_path: path to a valid metadata.xml file - @raise IOError: if C{metadata_path} can not be read - """ - - self.metadata_path = metadata_path - self._xml_tree = etree.parse(metadata_path) - - # Used for caching - self._herdstree = None - self._descriptions = None - self._maintainers = None - self._useflags = None - self._upstream = None - - def __repr__(self): - return "<%s %r>" % (self.__class__.__name__, self.metadata_path) + """Access metadata.xml""" + + def __init__(self, metadata_path): + """Parse a valid metadata.xml file. + + @type metadata_path: str + @param metadata_path: path to a valid metadata.xml file + @raise IOError: if C{metadata_path} can not be read + """ + + self.metadata_path = metadata_path + self._xml_tree = etree.parse(metadata_path) + + # Used for caching + self._herdstree = None + self._descriptions = None + self._maintainers = None + self._useflags = None + self._upstream = None + + def __repr__(self): + return "<%s %r>" % (self.__class__.__name__, self.metadata_path) + + def _get_herd_email(self, herd): + """Get a herd's email address. + + @type herd: str + @param herd: herd whose email you want + @rtype: str or None + @return: email address or None if herd is not in herds.xml + @raise IOError: if $PORTDIR/metadata/herds.xml can not be read + """ + + if self._herdstree is None: + herds_path = os.path.join(settings["PORTDIR"], "metadata/herds.xml") + try: + self._herdstree = etree.parse(herds_path) + except IOError: + # For some trees, herds.xml may not exist. Bug #300108. + return None + + # Some special herds are not listed in herds.xml + if herd in ("no-herd", "maintainer-wanted", "maintainer-needed"): + return None + + for node in self._herdstree.iter("herd"): + if node.findtext("name") == herd: + return node.findtext("email") + + def herds(self, include_email=False): + """Return a list of text nodes for <herd>. + + @type include_email: bool + @keyword include_email: if True, also look up the herd's email + @rtype: list + @return: if include_email is False, return a list of strings; + if include_email is True, return a list of tuples containing: + [('herd1', 'herd1@gentoo.org'), ('no-herd', None); + """ + + result = [] + for elem in self._xml_tree.findall("herd"): + text = elem.text + if text is None: + text = "" + if include_email: + herd_mail = self._get_herd_email(text) + result.append((text, herd_mail)) + else: + result.append(text) - def _get_herd_email(self, herd): - """Get a herd's email address. - - @type herd: str - @param herd: herd whose email you want - @rtype: str or None - @return: email address or None if herd is not in herds.xml - @raise IOError: if $PORTDIR/metadata/herds.xml can not be read - """ - - if self._herdstree is None: - herds_path = os.path.join(settings['PORTDIR'], 'metadata/herds.xml') - try: - self._herdstree = etree.parse(herds_path) - except IOError: - # For some trees, herds.xml may not exist. Bug #300108. - return None + return result - # Some special herds are not listed in herds.xml - if herd in ('no-herd', 'maintainer-wanted', 'maintainer-needed'): - return None + def descriptions(self): + """Return a list of text nodes for <longdescription>. - for node in self._herdstree.iter('herd'): - if node.findtext('name') == herd: - return node.findtext('email') + @rtype: list + @return: package description in string format + @todo: Support the C{lang} attribute + """ - def herds(self, include_email=False): - """Return a list of text nodes for <herd>. + if self._descriptions is not None: + return self._descriptions - @type include_email: bool - @keyword include_email: if True, also look up the herd's email - @rtype: list - @return: if include_email is False, return a list of strings; - if include_email is True, return a list of tuples containing: - [('herd1', 'herd1@gentoo.org'), ('no-herd', None); - """ + long_descriptions = self._xml_tree.findall("longdescription") + self._descriptions = [e.text for e in long_descriptions] + return self._descriptions - result = [] - for elem in self._xml_tree.findall('herd'): - text = elem.text - if text is None: - text = '' - if include_email: - herd_mail = self._get_herd_email(text) - result.append((text, herd_mail)) - else: - result.append(text) + def maintainers(self): + """Get maintainers' name, email and description. - return result + @rtype: list + @return: a sequence of L{_Maintainer} objects in document order. + """ - def descriptions(self): - """Return a list of text nodes for <longdescription>. + if self._maintainers is not None: + return self._maintainers - @rtype: list - @return: package description in string format - @todo: Support the C{lang} attribute - """ + self._maintainers = [] + for node in self._xml_tree.findall("maintainer"): + self._maintainers.append(_Maintainer(node)) - if self._descriptions is not None: - return self._descriptions + return self._maintainers - long_descriptions = self._xml_tree.findall("longdescription") - self._descriptions = [e.text for e in long_descriptions] - return self._descriptions + def use(self): + """Get names and descriptions for USE flags defined in metadata. - def maintainers(self): - """Get maintainers' name, email and description. + @rtype: list + @return: a sequence of L{_Useflag} objects in document order. + """ - @rtype: list - @return: a sequence of L{_Maintainer} objects in document order. - """ + if self._useflags is not None: + return self._useflags - if self._maintainers is not None: - return self._maintainers + self._useflags = [] + for node in self._xml_tree.iter("flag"): + self._useflags.append(_Useflag(node)) - self._maintainers = [] - for node in self._xml_tree.findall('maintainer'): - self._maintainers.append(_Maintainer(node)) + return self._useflags - return self._maintainers - - def use(self): - """Get names and descriptions for USE flags defined in metadata. - - @rtype: list - @return: a sequence of L{_Useflag} objects in document order. - """ - - if self._useflags is not None: - return self._useflags - - self._useflags = [] - for node in self._xml_tree.iter('flag'): - self._useflags.append(_Useflag(node)) + def upstream(self): + """Get upstream contact information. - return self._useflags + @rtype: list + @return: a sequence of L{_Upstream} objects in document order. + """ - def upstream(self): - """Get upstream contact information. + if self._upstream is not None: + return self._upstream - @rtype: list - @return: a sequence of L{_Upstream} objects in document order. - """ - - if self._upstream is not None: - return self._upstream + self._upstream = [] + for node in self._xml_tree.findall("upstream"): + self._upstream.append(_Upstream(node)) - self._upstream = [] - for node in self._xml_tree.findall('upstream'): - self._upstream.append(_Upstream(node)) + return self._upstream - return self._upstream # vim: set ts=4 sw=4 tw=79: |