Source code for tendril.utils.parsers.changelog

#!/usr/bin/env python
# encoding: utf-8

# Copyright (C) 2016 Chintalagiri Shashank
#
# This file is part of tendril.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
Docstring for changelog.py
"""

import arrow
from tendril.utils.files.markdown import parse_markdown
from tendril.utils.files.markdown import MarkdownTreeContainer


[docs]class ChangeLogParseError(Exception): pass
[docs]class ChangeLogNotFoundError(Exception): pass
[docs]class ChangeLogBase(object): child_marker = None child_marker_regex = None child_type = None has_title = False def __init__(self): self._title = None self._body = None self._children = []
[docs] def _set_title(self, title): if isinstance(title, tuple): title = title[1] if isinstance(title, MarkdownTreeContainer): self._title = title.collapse_to_text() else: self._title = title
[docs] def _check_for_marker(self, piece): if self.child_marker is not None: if piece[0] != self.child_marker: return False if self.child_marker_regex is not None: pass return True
[docs] def _populate(self, mdtree): if self.has_title is True: self._set_title(mdtree._pieces.pop(0)) if self.child_type is not None: subtree = None for piece in mdtree._pieces: if self._check_for_marker(piece): if subtree is not None: self._add_child(self.child_type(subtree)) subtree = MarkdownTreeContainer() subtree += piece elif subtree is not None: subtree += piece if subtree is not None: self._add_child(self.child_type(subtree)) else: self._body = mdtree.collapse_to_text()
[docs] def _add_child(self, child): self._children.append(child)
@property def title(self): return self._title
# A specific change
[docs]class ChangeLogChange(ChangeLogBase): has_title = False def __init__(self, mdtree): super(ChangeLogChange, self).__init__() # TODO Deal with structure in body self._populate(mdtree) def __repr__(self): return '<ChangeLogChange {}>'.format(self._body) @property def body(self): return self._body
# A specific changelog entry
[docs]class ChangeLogEntry(ChangeLogBase): def __init__(self, mdtree): super(ChangeLogEntry, self).__init__() self._date = None self._author = None self._email = None self._populate(mdtree) @property def changes(self): return self._children @property def initials(self): return ''.join([x[0] for x in self._author.split()]) @property def date(self): return self._date
[docs] def _set_title(self, title): pieces = title[1]._pieces piece = pieces.pop(0) sdate, sname = piece[1].strip().split(' ', 1) self._date = arrow.get(sdate.strip()) self._author = sname.strip() piece = pieces.pop(0) self._email = piece[2]
[docs] def _populate(self, mdtree): self._set_title(mdtree._pieces.pop(0)) piece = mdtree._pieces.pop(0) clist = piece[1] for item in clist._pieces: if item[0] == 'list_item': self._children.append(ChangeLogChange(item[1]))
def __repr__(self): return '<ChangeLogEntry {}>'.format(self._date)
# A specific release
[docs]class ChangeLogSection(ChangeLogBase): child_marker = 'paragraph' child_marker_regex = '' child_type = ChangeLogEntry has_title = True def __init__(self, mdtree): super(ChangeLogSection, self).__init__() self._populate(mdtree) @property def entries(self): return self._children def __repr__(self): return '<ChangeLogSection {}>'.format(self._title)
# ChangeLog of a specific Part, relevent when a project is forked to create a # new project.
[docs]class ChangeLogPart(ChangeLogBase): child_marker = 'h3' child_type = ChangeLogSection has_title = True def __init__(self, mdtree): super(ChangeLogPart, self).__init__() self._populate(mdtree) @property def sections(self): return self._children def __repr__(self): return '<ChangeLogPart {}>'.format(self._title)
# Specific ChangeLog File
[docs]class ChangeLog(ChangeLogBase): child_marker = 'h2' child_type = ChangeLogPart has_title = False def __init__(self, fpath): super(ChangeLog, self).__init__() self._fpath = fpath try: mdtree = parse_markdown(self._fpath) except IOError: raise ChangeLogNotFoundError(fpath) except NotImplementedError: raise ChangeLogParseError("Unsupported formatting found in {}".format(fpath)) self._populate(mdtree) @property def parts(self): return self._children def __repr__(self): return '<ChangeLog from {}>'.format(self._fpath)
[docs]def get_changelog(fpath): cl = ChangeLog(fpath) return cl