summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2018-08-24 19:24:07 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2018-08-24 19:32:47 (GMT)
commit5b49acb829c3fd077f7946ef8a3ba6ee3d6de888 (patch) (side-by-side diff)
tree578ad2dd0be9b0aa952ba43a02e0ad1d25359cd6
parentb14aa091903560d2f156e6f3549d373c65fe3b2d (diff)
downloadreleaselogparser-5b49acb829c3fd077f7946ef8a3ba6ee3d6de888.tar.gz
releaselogparser-5b49acb829c3fd077f7946ef8a3ba6ee3d6de888.tar.bz2
Implement Python-style release log format
* releaselog.py (main): Explicitly add newline characters. * releaselog/__init__.py (end_of_entry_rx): New attribute. (parse_header): Return a triple: (date, version, line), where line is first line of the description or None. (is_end_of_entry): New method. (__init__): Strip trailing newline from the description lines. * releaselog/format/python.py: New file.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--releaselog.py2
-rw-r--r--releaselog/__init__.py32
-rw-r--r--releaselog/format/python.py54
3 files changed, 81 insertions, 7 deletions
diff --git a/releaselog.py b/releaselog.py
index 3109787..c8eeff3 100644
--- a/releaselog.py
+++ b/releaselog.py
@@ -49,7 +49,7 @@ def main():
count=options.count)
for r in cl:
print(r)
- print(''.join(r.descr))
+ print('\n'.join(r.descr))
if __name__ == '__main__':
main()
diff --git a/releaselog/__init__.py b/releaselog/__init__.py
index dfee183..7cb9c7d 100644
--- a/releaselog/__init__.py
+++ b/releaselog/__init__.py
@@ -44,9 +44,13 @@ class ReleaseHistory(object):
history - a list of Release objects
header - a compiled regular expression that returns a match for
history entry heading lines
+ end_of_entry_rx - a compiled regular expression returning a match for
+ end of entry. Can be None
"""
history = []
+
+ end_of_entry_rx = re.compile('^(\f|^\s*=+\s*$)')
def __len__(self):
return len(self.history)
@@ -62,16 +66,30 @@ class ReleaseHistory(object):
raise TypeError()
def parse_header(self, line):
- """Matches line against the history header regexp. On match, returns
- a tuple (date, version). On failure, returns (None, None).
+ """Matche input line against the history header regexp. On match,
+ return a tuple (date, version, startdescr), where date is the
+ release date (datetime), version is the release version number, and
+ startdescr is the first line of the description or None.
+ On failure, return (None, None, None).
"""
date = None
version = None
+ rest = None
m = self.header.match(line)
if m:
version = m.group('version')
date = dateparser.parse(m.group('date'))
- return date, version
+ try:
+ rest = m.group('rest')
+ if len(rest) == 0:
+ rest = None
+ except IndexError:
+ pass
+ return date, version, rest
+
+ def is_end_of_entry(self, line):
+ return (self.end_of_entry_rx.match(line)
+ if self.end_of_entry_rx else False)
def __init__(self, lines, **kwargs):
"""Create a new history object from the list of lines. The list is
@@ -134,7 +152,7 @@ class ReleaseHistory(object):
i = 0
for line in lines:
- (d, v) = self.parse_header(line)
+ (d, v, r) = self.parse_header(line)
if d:
if date:
self.append(Release(version, date, descr))
@@ -151,14 +169,16 @@ class ReleaseHistory(object):
date = d
version = v
descr = []
- elif re.match('^(\f|^\s*=+\s*$)', line):
+ if r:
+ descr.append(r)
+ elif self.is_end_of_entry(line):
if date:
self.append(Release(version, date, descr))
date = None
version = None
descr = []
elif date:
- descr.append(line)
+ descr.append(line.rstrip("\n"))
if date:
self.append(Release(version, date, descr))
diff --git a/releaselog/format/python.py b/releaselog/format/python.py
new file mode 100644
index 0000000..7c2a218
--- a/dev/null
+++ b/releaselog/format/python.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+"""
+Implementation of two release log formats used in most Python packages.
+
+The two formats are:
+
+* Each entry begins with the line
+
+ v<Version>, <Date> -- <String>
+
+where <String> is the beginning of the description. More description lines
+may follow.
+
+* Each entry begins with the line
+
+ <Version> (<Date>)
+
+followed by the description text. This format is used, among others, by
+GNU Texinfo.
+
+The PythonLogFormat class discovers the actual format by finding the first
+input line that matches any of the above patterns.
+
+"""
+
+import re
+from releaselog import ReleaseHistory
+
+class PythonLogFormat(ReleaseHistory):
+ format = ['Python', 'python']
+ header = None
+ header_rx = [
+ re.compile("""^[vV](?P<version>\d[\d.]*)\s*
+ ,\s*
+ (?P<date>.*?)
+ \s+-+\s*
+ (?P<rest>.*)$
+ """, re.X),
+ re.compile("""^(?P<version>\d[\d.]*)
+ \s*
+ (?P<date>.*)
+ """, re.X)
+ ]
+
+ def parse_header(self, line):
+ if self.header:
+ return super(PythonLogFormat, self).parse_header(line)
+ else:
+ for rx in self.header_rx:
+ if rx.match(line):
+ self.header = rx
+ return super(PythonLogFormat, self).parse_header(line)
+ return (None, None, None)
+

Return to:

Send suggestions and report system problems to the System administrator.