Browse Source

Teach format_changelog to sort and collate sections.

Give it options to turn off collation and/or wrapping.
Nick Mathewson 10 years ago
parent
commit
45f534e6df
1 changed files with 99 additions and 10 deletions
  1. 99 10
      scripts/maint/format_changelog.py

+ 99 - 10
scripts/maint/format_changelog.py

@@ -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
-
-if len(sys.argv) == 1:
+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")
+
+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)