##// END OF EJS Templates
scripts: fix crash from comparing integer with empty list...
Mads Kiilerich -
r8179:d6ccf6a9 default
parent child Browse files
Show More
@@ -1,179 +1,182 b''
1 1 #!/usr/bin/env python3
2 2 # -*- coding: utf-8 -*-
3 3
4 4 """
5 5 Kallithea script for maintaining contributor lists from version control
6 6 history.
7 7
8 8 This script and the data in it is a best effort attempt at reverse engineering
9 9 previous attributions and correlate that with version control history while
10 10 preserving all existing copyright statements and attribution. This script is
11 11 processing and summarizing information found elsewhere - it is not by itself
12 12 making any claims. Comments in the script are an attempt at reverse engineering
13 13 possible explanations - they are not showing any intent or confirming it is
14 14 correct.
15 15
16 16 Three files are generated / modified by this script:
17 17
18 18 kallithea/templates/about.html claims to show copyright holders, and the GPL
19 19 license requires such existing "legal notices" to be preserved. We also try to
20 20 keep it updated with copyright holders, but do not claim it is a correct list.
21 21
22 22 CONTRIBUTORS has the purpose of giving credit where credit is due and list all
23 23 the contributor names in the source.
24 24
25 25 kallithea/templates/base/base.html contains the copyright years in the page
26 26 footer.
27 27
28 28 Both make a best effort of listing all copyright holders, but revision control
29 29 history might be a better and more definitive source.
30 30
31 31 Contributors are sorted "fairly" by copyright year and amount of
32 32 contribution.
33 33
34 34 New contributors are listed, without considering if the contribution contains
35 35 copyrightable work.
36 36
37 37 When the copyright might belong to a different legal entity than the
38 38 contributor, the legal entity is given credit too.
39 39 """
40 40
41 41 import os
42 42 import re
43 43 from collections import defaultdict
44 44
45 45 import contributor_data
46 46
47 47
48 48 def sortkey(x):
49 49 """Return key for sorting contributors "fairly":
50 50 * latest contribution
51 51 * first contribution
52 52 * number of contribution years
53 53 * name (with some unicode normalization)
54 54 The entries must be 2-tuples of a list of string years and the name"""
55 return (x[0] and -int(x[0][-1]),
56 x[0] and int(x[0][0]),
57 -len(x[0]),
58 x[1].decode('utf-8').lower().replace('\xe9', 'e').replace('\u0142', 'l')
55 years, name = x
56 if not years:
57 years = ['0']
58 return (-int(years[-1]), # primarily sort by latest contribution
59 int(years[0]), # then sort by first contribution
60 -len(years), # then sort by length of contribution (no gaps)
61 name.lower().replace('\xe9', 'e').replace('\u0142', 'l') # finally sort by name
59 62 )
60 63
61 64
62 65 def nice_years(l, dash='-', join=' '):
63 66 """Convert a list of years into brief range like '1900-1901, 1921'."""
64 67 if not l:
65 68 return ''
66 69 start = end = int(l[0])
67 70 ranges = []
68 71 for year in l[1:] + [0]:
69 72 year = int(year)
70 73 if year == end + 1:
71 74 end = year
72 75 continue
73 76 if start == end:
74 77 ranges.append('%s' % start)
75 78 else:
76 79 ranges.append('%s%s%s' % (start, dash, end))
77 80 start = end = year
78 81 assert start == 0 and end == 0, (start, end)
79 82 return join.join(ranges)
80 83
81 84
82 85 def insert_entries(
83 86 filename,
84 87 all_entries,
85 88 no_entries,
86 89 domain_extra,
87 90 split_re,
88 91 normalize_name,
89 92 format_f):
90 93 """Update file with contributor information.
91 94 all_entries: list of tuples with year and name
92 95 no_entries: set of names or name and year tuples to ignore
93 96 domain_extra: map domain name to extra credit name
94 97 split_re: regexp matching the part of file to rewrite
95 98 normalize_name: function to normalize names for grouping and display
96 99 format_f: function formatting year list and name to a string
97 100 """
98 101 name_years = defaultdict(set)
99 102
100 103 for year, name in all_entries:
101 104 if name in no_entries or (name, year) in no_entries:
102 105 continue
103 106 parts = name.split(' <', 1)
104 107 if len(parts) == 2:
105 108 name = parts[0] + ' <' + parts[1].lower()
106 109 domain = name.split('@', 1)[-1].rstrip('>')
107 110 if domain in domain_extra:
108 111 name_years[domain_extra[domain]].add(year)
109 112 name_years[normalize_name(name)].add(year)
110 113
111 114 l = [(list(sorted(year for year in years if year)), name)
112 115 for name, years in name_years.items()]
113 116 l.sort(key=sortkey)
114 117
115 118 with open(filename) as f:
116 119 pre, post = re.split(split_re, f.read())
117 120
118 121 with open(filename, 'w') as f:
119 122 f.write(pre +
120 123 ''.join(format_f(years, name) for years, name in l) +
121 124 post)
122 125
123 126
124 127 def main():
125 128 repo_entries = [
126 129 (year, contributor_data.name_fixes.get(name) or contributor_data.name_fixes.get(name.rsplit('<', 1)[0].strip()) or name)
127 130 for year, name in
128 131 (line.strip().split(' ', 1)
129 132 for line in os.popen("""hg log -r '::.' -T '{date(date,"%Y")} {author}\n'""").readlines())
130 133 ]
131 134
132 135 insert_entries(
133 136 filename='kallithea/templates/about.html',
134 137 all_entries=repo_entries + contributor_data.other_about + contributor_data.other,
135 138 no_entries=contributor_data.no_about,
136 139 domain_extra=contributor_data.domain_extra,
137 140 split_re=r'(?: <li>Copyright &copy; [^\n]+</li>\n)+',
138 141 normalize_name=lambda name: name.split('<', 1)[0].strip(),
139 142 format_f=lambda years, name: ' <li>Copyright &copy; %s, %s</li>\n' % (nice_years(years, '&ndash;', ', '), name),
140 143 )
141 144
142 145 insert_entries(
143 146 filename='CONTRIBUTORS',
144 147 all_entries=repo_entries + contributor_data.other_contributors + contributor_data.other,
145 148 no_entries=contributor_data.total_ignore,
146 149 domain_extra=contributor_data.domain_extra,
147 150 split_re=r'(?: [^\n]+\n)+',
148 151 normalize_name=lambda name: name,
149 152 format_f=lambda years, name: (' %s%s%s\n' % (name, ' ' if years else '', nice_years(years))),
150 153 )
151 154
152 155 insert_entries(
153 156 filename='kallithea/templates/base/base.html',
154 157 all_entries=repo_entries,
155 158 no_entries=contributor_data.total_ignore,
156 159 domain_extra={},
157 160 split_re=r'(?<=&copy;) .+ (?=by various authors)',
158 161 normalize_name=lambda name: '',
159 162 format_f=lambda years, name: ' ' + nice_years(years, '&ndash;', ', ') + ' ',
160 163 )
161 164
162 165 #docs/conf.py:copyright = u'2010-2016 by various authors, licensed as GPLv3.'
163 166 insert_entries(
164 167 filename='docs/conf.py',
165 168 all_entries=repo_entries,
166 169 no_entries=contributor_data.total_ignore,
167 170 domain_extra={},
168 171 split_re=r"(?<=copyright = ').+(?= by various authors)",
169 172 normalize_name=lambda name: '',
170 173 format_f=lambda years, name: nice_years(years, '-', ', '),
171 174 )
172 175
173 176
174 177 if __name__ == '__main__':
175 178 main()
176 179
177 180
178 181 # To list new contributors since last tagging:
179 182 # { hg log -r '::tagged()' -T ' {author}\n {author}\n'; hg log -r '::.' -T ' {author}\n' | sort | uniq; } | sort | uniq -u
General Comments 0
You need to be logged in to leave comments. Login now