sortChanges.py (3030B)
1 #!/usr/bin/env python 2 # Copyright (c) 2014-2019, The Tor Project, Inc. 3 # See LICENSE for licensing information 4 5 """This script sorts a bunch of changes files listed on its command 6 line into roughly the order in which they should appear in the 7 changelog. 8 """ 9 10 # Future imports for Python 2.7, mandatory in 3.0 11 from __future__ import division 12 from __future__ import print_function 13 from __future__ import unicode_literals 14 15 import re 16 import sys 17 18 def fetch(fn): 19 with open(fn) as f: 20 s = f.read() 21 s = "%s\n" % s.rstrip() 22 return s 23 24 CSR='Code simplification and refactoring' 25 26 REPLACEMENTS = { 27 # plurals 28 'Minor bugfix' : 'Minor bugfixes', 29 'Major bugfix' : 'Major bugfixes', 30 'Minor feature' : 'Minor features', 31 'Major feature' : 'Major features', 32 'Removed feature' : 'Removed features', 33 'Code simplification and refactorings' : CSR, 34 'Code simplifications and refactoring' : CSR, 35 'Code simplifications and refactorings' : CSR, 36 37 # wrong words 38 'Minor fix' : 'Minor bugfixes', 39 'Major fix' : 'Major bugfixes', 40 'Minor fixes' : 'Minor bugfixes', 41 'Major fixes' : 'Major bugfixes', 42 'Minor enhancement' : 'Minor features', 43 'Minor enhancements' : 'Minor features', 44 'Major enhancement' : 'Major features', 45 'Major enhancements' : 'Major features', 46 } 47 48 def score(s,fname=None): 49 m = re.match(r'^ +o ([^\n]*)\n(.*)', s, re.M|re.S) 50 if not m: 51 print("Can't score %r from %s"%(s,fname), file=sys.stderr) 52 heading = m.group(1) 53 heading = REPLACEMENTS.get(heading, heading) 54 lw = m.group(1).lower() 55 if lw.startswith("major feature"): 56 score = 0 57 elif lw.startswith("major bug"): 58 score = 1 59 elif lw.startswith("major"): 60 score = 2 61 elif lw.startswith("minor feature"): 62 score = 10 63 elif lw.startswith("minor bug"): 64 score = 11 65 elif lw.startswith("minor"): 66 score = 12 67 else: 68 score = 100 69 70 return (score, lw, heading, m.group(2)) 71 72 def splitChanges(s): 73 this_entry = [] 74 for line in s.split("\n"): 75 if line.strip() == "": 76 continue 77 if re.match(r" +o ", line): 78 if len(this_entry) > 2: 79 yield "".join(this_entry) 80 curHeader = line 81 this_entry = [ curHeader, "\n" ] 82 continue 83 elif re.match(r" +- ", line): 84 if len(this_entry) > 2: 85 yield "".join(this_entry) 86 this_entry = [ curHeader, "\n" ] 87 88 this_entry.append(line) 89 this_entry.append("\n") 90 91 if len(this_entry) > 2: 92 yield "".join(this_entry) 93 94 95 changes = [] 96 97 for fn in sys.argv[1:]: 98 if fn.endswith('~'): 99 continue 100 for change in splitChanges(fetch(fn)): 101 changes.append(score(change,fn)) 102 103 changes.sort() 104 105 last_lw = "this is not a header" 106 for _, lw, header, rest in changes: 107 if lw == last_lw: 108 print(rest, end="") 109 else: 110 print() 111 print(" o",header) 112 print(rest, end="") 113 last_lw = lw