Teach format_changelog to sort and collate sections.

Give it options to turn off collation and/or wrapping.
This commit is contained in:
Nick Mathewson 2014-10-19 12:44:19 -04:00
parent 1405fbcc58
commit 45f534e6df
1 changed files with 98 additions and 9 deletions

View File

@ -12,6 +12,7 @@
import os
import re
import sys
import optparse
# ==============================
# Oh, look! It's a cruddy approximation to Knuth's elegant text wrapping
@ -186,8 +187,49 @@ def body_parser(line):
else:
print "Weird line %r"%line
def clean_head(head):
return head
def head_score(s):
m = re.match(r'^ +o (.*)', s)
if not m:
print >>sys.stderr, "Can't score %r"%s
return 99999
lw = m.group(1).lower()
if lw.startswith("security") and "feature" not in lw:
score = -300
elif lw.startswith("deprecated versions"):
score = -200
elif "build require" in lw:
score = -100
elif lw.startswith("major feature"):
score = 00
elif lw.startswith("major bug"):
score = 50
elif lw.startswith("major"):
score = 70
elif lw.startswith("minor feature"):
score = 200
elif lw.startswith("minor bug"):
score = 250
elif lw.startswith("minor"):
score = 270
else:
score = 1000
if 'secur' in lw:
score -= 2
if "(other)" in lw:
score += 2
if '(' not in lw:
score -= 1
return score
class ChangeLog(object):
def __init__(self):
def __init__(self, wrapText=True):
self.prehead = []
self.mainhead = None
self.headtext = []
@ -195,6 +237,7 @@ class ChangeLog(object):
self.sections = []
self.cursection = None
self.lineno = 0
self.wrapText = wrapText
def addLine(self, tp, line):
self.lineno += 1
@ -249,6 +292,11 @@ class ChangeLog(object):
self.lint_item(item_line, grafs, head_type)
def dumpGraf(self,par,indent1,indent2=-1):
if not self.wrapText:
for line in par:
print line
return
if indent2 == -1:
indent2 = indent1
text = " ".join(re.sub(r'\s+', ' ', line.strip()) for line in par)
@ -258,6 +306,22 @@ class ChangeLog(object):
initial_indent=" "*indent1,
subsequent_indent=" "*indent2))
def collateAndSortSections(self):
heads = []
sectionsByHead = { }
for _, head, items in self.sections:
head = clean_head(head)
try:
s = sectionsByHead[head]
except KeyError:
s = sectionsByHead[head] = []
heads.append( (head_score(head), head, s) )
s.extend(items)
heads.sort()
self.sections = [ (0, head, items) for _,head,items in heads ]
def dump(self):
if self.prehead:
self.dumpGraf(self.prehead, 0)
@ -279,20 +343,36 @@ class ChangeLog(object):
print
print
CL = ChangeLog()
parser = head_parser
op = optparse.OptionParser(usage="usage: %prog [options] [filename]")
op.add_option('-W', '--no-wrap', action='store_false',
dest='wrapText', default=True,
help='Do not re-wrap paragraphs')
op.add_option('-S', '--no-sort', action='store_false',
dest='sort', default=True,
help='Do not sort or collate sections')
op.add_option('-o', '--output', dest='output',
default=None, metavar='FILE', help="write output to FILE")
if len(sys.argv) == 1:
options,args = op.parse_args()
if len(args) > 1:
op.error("Too many arguments")
elif len(args) == 0:
fname = 'ChangeLog'
else:
fname = sys.argv[1]
fname = args[0]
fname_new = fname+".new"
if options.output == None:
options.output = fname
sys.stdin = open(fname, 'r')
if fname != '-':
sys.stdin = open(fname, 'r')
nextline = None
CL = ChangeLog(wrapText=options.wrapText)
parser = head_parser
for line in sys.stdin:
line = line.rstrip()
tp = parser(line)
@ -307,7 +387,15 @@ for line in sys.stdin:
CL.lint()
sys.stdout = open(fname_new, 'w')
if options.output != '-':
fname_new = options.output+".new"
fname_out = options.output
sys.stdout = open(fname_new, 'w')
else:
fname_new = fname_out = None
if options.sort:
CL.collateAndSortSections()
CL.dump()
@ -317,4 +405,5 @@ if nextline is not None:
for line in sys.stdin:
sys.stdout.write(line)
os.rename(fname_new, fname)
if fname_new is not None:
os.rename(fname_new, fname_out)