main: Specialize the periodic events on a per-role basis
[tor.git] / scripts / maint / sortChanges.py
blob22e40fd369ae973b91e56207a71a105cb0555fa7
1 #!/usr/bin/python
2 # Copyright (c) 2014-2017, The Tor Project, Inc.
3 # See LICENSE for licensing information
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 """
10 import re
11 import sys
13 def fetch(fn):
14 with open(fn) as f:
15 s = f.read()
16 s = "%s\n" % s.rstrip()
17 return s
19 CSR='Code simplification and refactoring'
21 REPLACEMENTS = {
22 # plurals
23 'Minor bugfix' : 'Minor bugfixes',
24 'Major bugfix' : 'Major bugfixes',
25 'Minor feature' : 'Minor features',
26 'Major feature' : 'Major features',
27 'Removed feature' : 'Removed features',
28 'Code simplification and refactorings' : CSR,
29 'Code simplifications and refactoring' : CSR,
30 'Code simplifications and refactorings' : CSR,
32 # wrong words
33 'Minor fix' : 'Minor bugfixes',
34 'Major fix' : 'Major bugfixes',
35 'Minor fixes' : 'Minor bugfixes',
36 'Major fixes' : 'Major bugfixes',
37 'Minor enhancement' : 'Minor features',
38 'Minor enhancements' : 'Minor features',
39 'Major enhancement' : 'Major features',
40 'Major enhancements' : 'Major features',
43 def score(s,fname=None):
44 m = re.match(r'^ +o ([^\n]*)\n(.*)', s, re.M|re.S)
45 if not m:
46 print >>sys.stderr, "Can't score %r from %s"%(s,fname)
47 heading = m.group(1)
48 heading = REPLACEMENTS.get(heading, heading)
49 lw = m.group(1).lower()
50 if lw.startswith("major feature"):
51 score = 0
52 elif lw.startswith("major bug"):
53 score = 1
54 elif lw.startswith("major"):
55 score = 2
56 elif lw.startswith("minor feature"):
57 score = 10
58 elif lw.startswith("minor bug"):
59 score = 11
60 elif lw.startswith("minor"):
61 score = 12
62 else:
63 score = 100
65 return (score, lw, heading, m.group(2))
67 def splitChanges(s):
68 this_entry = []
69 for line in s.split("\n"):
70 if line.strip() == "":
71 continue
72 if re.match(r" +o ", line):
73 if len(this_entry) > 2:
74 yield "".join(this_entry)
75 curHeader = line
76 this_entry = [ curHeader, "\n" ]
77 continue
78 elif re.match(r" +- ", line):
79 if len(this_entry) > 2:
80 yield "".join(this_entry)
81 this_entry = [ curHeader, "\n" ]
83 this_entry.append(line)
84 this_entry.append("\n")
86 if len(this_entry) > 2:
87 yield "".join(this_entry)
90 changes = []
92 for fn in sys.argv[1:]:
93 if fn.endswith('~'):
94 continue
95 for change in splitChanges(fetch(fn)):
96 changes.append(score(change,fn))
98 changes.sort()
100 last_lw = "this is not a header"
101 for _, lw, header, rest in changes:
102 if lw == last_lw:
103 print rest,
104 else:
105 print
106 print " o",header
107 print rest,
108 last_lw = lw