Show More
@@ -0,0 +1,253 b'' | |||||
|
1 | #!/usr/bin/env python2 | |||
|
2 | # -*- coding: utf-8 -*- | |||
|
3 | ||||
|
4 | """ | |||
|
5 | Kallithea script for maintaining contributor lists from version control | |||
|
6 | history. | |||
|
7 | ||||
|
8 | This script and the data in it is a best effort attempt at reverse engineering | |||
|
9 | previous attributions and correlate that with version control history while | |||
|
10 | preserving all existing copyright statements and attribution. This script is | |||
|
11 | processing and summarizing information found elsewhere - it is not by itself | |||
|
12 | making any claims. Comments in the script are an attempt at reverse engineering | |||
|
13 | possible explanations - they are not showing any intent or confirming it is | |||
|
14 | correct. | |||
|
15 | ||||
|
16 | Three files are generated / modified by this script: | |||
|
17 | ||||
|
18 | kallithea/templates/about.html claims to show copyright holders, and the GPL | |||
|
19 | license requires such existing "legal notices" to be preserved. We also try to | |||
|
20 | keep it updated with copyright holders, but do not claim it is a correct list. | |||
|
21 | ||||
|
22 | CONTRIBUTORS has the purpose of giving credit where credit is due and list all | |||
|
23 | the contributor names in the source. | |||
|
24 | ||||
|
25 | kallithea/templates/base/base.html contains the copyright years in the page | |||
|
26 | footer. | |||
|
27 | ||||
|
28 | Both make a best effort of listing all copyright holders, but revision control | |||
|
29 | history might be a better and more definitive source. | |||
|
30 | ||||
|
31 | Contributors are sorted "fairly" by copyright year and amount of | |||
|
32 | contribution. | |||
|
33 | ||||
|
34 | New contributors are listed, without considering if the contribution contains | |||
|
35 | copyrightable work. | |||
|
36 | ||||
|
37 | When the copyright might belong to a different legal entity than the | |||
|
38 | contributor, the legal entity is given credit too. | |||
|
39 | """ | |||
|
40 | ||||
|
41 | ||||
|
42 | # Some committers are so wrong that it doesn't point at any contributor: | |||
|
43 | total_ignore = set() | |||
|
44 | total_ignore.add('*** failed to import extension hggit: No module named hggit') | |||
|
45 | total_ignore.add('<>') | |||
|
46 | ||||
|
47 | # Normalize some committer names where people have contributed under different | |||
|
48 | # names or email addresses: | |||
|
49 | name_fixes = {} | |||
|
50 | name_fixes['Andrew Shadura'] = "Andrew Shadura <andrew@shadura.me>" | |||
|
51 | name_fixes['aparkar'] = "Aparkar <aparkar@icloud.com>" | |||
|
52 | name_fixes['Aras Pranckevicius'] = "Aras Pranckevičius <aras@unity3d.com>" | |||
|
53 | name_fixes['Augosto Hermann'] = "Augusto Herrmann <augusto.herrmann@planejamento.gov.br>" | |||
|
54 | name_fixes['"Bradley M. Kuhn" <bkuhn@ebb.org>'] = "Bradley M. Kuhn <bkuhn@sfconservancy.org>" | |||
|
55 | name_fixes['dmitri.kuznetsov'] = "Dmitri Kuznetsov" | |||
|
56 | name_fixes['Dmitri Kuznetsov'] = "Dmitri Kuznetsov" | |||
|
57 | name_fixes['domruf'] = "Dominik Ruf <dominikruf@gmail.com>" | |||
|
58 | name_fixes['Ingo von borstel'] = "Ingo von Borstel <kallithea@planetmaker.de>" | |||
|
59 | name_fixes['Jan Heylen'] = "Jan Heylen <heyleke@gmail.com>" | |||
|
60 | name_fixes['Jason F. Harris'] = "Jason Harris <jason@jasonfharris.com>" | |||
|
61 | name_fixes['Jelmer Vernooij'] = "Jelmer Vernooij <jelmer@samba.org>" | |||
|
62 | name_fixes['jfh <jason@jasonfharris.com>'] = "Jason Harris <jason@jasonfharris.com>" | |||
|
63 | name_fixes['Leonardo Carneiro<leonardo@unity3d.com>'] = "Leonardo Carneiro <leonardo@unity3d.com>" | |||
|
64 | name_fixes['leonardo'] = "Leonardo Carneiro <leonardo@unity3d.com>" | |||
|
65 | name_fixes['Leonardo <leo@unity3d.com>'] = "Leonardo Carneiro <leonardo@unity3d.com>" | |||
|
66 | name_fixes['Les Peabody'] = "Les Peabody <lpeabody@gmail.com>" | |||
|
67 | name_fixes['"Lorenzo M. Catucci" <lorenzo@sancho.ccd.uniroma2.it>'] = "Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>" | |||
|
68 | name_fixes['Lukasz Balcerzak'] = "Łukasz Balcerzak <lukaszbalcerzak@gmail.com>" | |||
|
69 | name_fixes['mao <mao@lins.fju.edu.tw>'] = "Ching-Chen Mao <mao@lins.fju.edu.tw>" | |||
|
70 | name_fixes['marcink'] = "Marcin Kuźmiński <marcin@python-works.com>" | |||
|
71 | name_fixes['Marcin Kuzminski'] = "Marcin Kuźmiński <marcin@python-works.com>" | |||
|
72 | name_fixes['nansenat16@null.tw'] = "nansenat16 <nansenat16@null.tw>" | |||
|
73 | name_fixes['Peter Vitt'] = "Peter Vitt <petervitt@web.de>" | |||
|
74 | name_fixes['philip.j@hostdime.com'] = "Philip Jameson <philip.j@hostdime.com>" | |||
|
75 | name_fixes['Søren Løvborg'] = "Søren Løvborg <sorenl@unity3d.com>" | |||
|
76 | name_fixes['Thomas De Schampheleire'] = "Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>" | |||
|
77 | name_fixes['Weblate'] = "<>" | |||
|
78 | name_fixes['xpol'] = "xpol <xpolife@gmail.com>" | |||
|
79 | ||||
|
80 | ||||
|
81 | # Some committer email address domains that indicate that another entity might | |||
|
82 | # hold some copyright too: | |||
|
83 | domain_extra = {} | |||
|
84 | domain_extra['unity3d.com'] = "Unity Technologies" | |||
|
85 | domain_extra['rhodecode.com'] = "RhodeCode GmbH" | |||
|
86 | ||||
|
87 | # Repository history show some old contributions that traditionally hasn't been | |||
|
88 | # listed in about.html - preserve that: | |||
|
89 | no_about = set(total_ignore) | |||
|
90 | # The following contributors were traditionally not listed in about.html and it | |||
|
91 | # seems unclear if the copyright is personal or belongs to a company. | |||
|
92 | no_about.add(('Thayne Harbaugh <thayne@fusionio.com>', '2011')) | |||
|
93 | no_about.add(('Dies Koper <diesk@fast.au.fujitsu.com>', '2012')) | |||
|
94 | no_about.add(('Erwin Kroon <e.kroon@smartmetersolutions.nl>', '2012')) | |||
|
95 | no_about.add(('Vincent Caron <vcaron@bearstech.com>', '2012')) | |||
|
96 | # These contributors' contributions might be too small to be copyrightable: | |||
|
97 | no_about.add(('philip.j@hostdime.com', '2012')) | |||
|
98 | no_about.add(('Stefan Engel <mail@engel-stefan.de>', '2012')) | |||
|
99 | no_about.add(('Ton Plomp <tcplomp@gmail.com>', '2013')) | |||
|
100 | # Was reworked and contributed later and shadowed by other contributions: | |||
|
101 | no_about.add(('Sean Farley <sean.michael.farley@gmail.com>', '2013')) | |||
|
102 | ||||
|
103 | # Preserve contributors listed in about.html but not appearing in repository | |||
|
104 | # history: | |||
|
105 | other_about = [ | |||
|
106 | ("2011", "Aparkar <aparkar@icloud.com>"), | |||
|
107 | ("2010", "RhodeCode GmbH"), | |||
|
108 | ("2011", "RhodeCode GmbH"), | |||
|
109 | ("2012", "RhodeCode GmbH"), | |||
|
110 | ("2013", "RhodeCode GmbH"), | |||
|
111 | ] | |||
|
112 | ||||
|
113 | # Preserve contributors listed in CONTRIBUTORS but not appearing in repository | |||
|
114 | # history: | |||
|
115 | other_contributors = [ | |||
|
116 | ("", "Andrew Kesterson <andrew@aklabs.net>"), | |||
|
117 | ("", "cejones"), | |||
|
118 | ("", "David A. Sjøen <david.sjoen@westcon.no>"), | |||
|
119 | ("", "James Rhodes <jrhodes@redpointsoftware.com.au>"), | |||
|
120 | ("", "Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>"), | |||
|
121 | ("", "larikale"), | |||
|
122 | ("", "RhodeCode GmbH"), | |||
|
123 | ("", "Sebastian Kreutzberger <sebastian@rhodecode.com>"), | |||
|
124 | ("", "Steve Romanow <slestak989@gmail.com>"), | |||
|
125 | ("", "SteveCohen"), | |||
|
126 | ("", "Thomas <thomas@rhodecode.com>"), | |||
|
127 | ("", "Thomas Waldmann <tw-public@gmx.de>"), | |||
|
128 | ] | |||
|
129 | ||||
|
130 | ||||
|
131 | import os | |||
|
132 | import re | |||
|
133 | from collections import defaultdict | |||
|
134 | ||||
|
135 | ||||
|
136 | def sortkey(x): | |||
|
137 | """Return key for sorting contributors "fairly": | |||
|
138 | * latest contribution | |||
|
139 | * first contribution | |||
|
140 | * number of contribution years | |||
|
141 | * name (with some unicode normalization) | |||
|
142 | The entries must be 2-tuples of a list of string years and the unicode name""" | |||
|
143 | return (x[0] and -int(x[0][-1]), | |||
|
144 | x[0] and int(x[0][0]), | |||
|
145 | -len(x[0]), | |||
|
146 | x[1].decode('utf8').lower().replace(u'\xe9', u'e').replace(u'\u0142', u'l') | |||
|
147 | ) | |||
|
148 | ||||
|
149 | ||||
|
150 | def nice_years(l, dash='-', join=' '): | |||
|
151 | """Convert a list of years into brief range like '1900-1901, 1921'.""" | |||
|
152 | if not l: | |||
|
153 | return '' | |||
|
154 | start = end = int(l[0]) | |||
|
155 | ranges = [] | |||
|
156 | for year in l[1:] + [0]: | |||
|
157 | year = int(year) | |||
|
158 | if year == end + 1: | |||
|
159 | end = year | |||
|
160 | continue | |||
|
161 | if start == end: | |||
|
162 | ranges.append('%s' % start) | |||
|
163 | else: | |||
|
164 | ranges.append('%s%s%s' % (start, dash, end)) | |||
|
165 | start = end = year | |||
|
166 | assert start == 0 and end == 0, (start, end) | |||
|
167 | return join.join(ranges) | |||
|
168 | ||||
|
169 | ||||
|
170 | def insert_entries( | |||
|
171 | filename, | |||
|
172 | all_entries, | |||
|
173 | no_entries, | |||
|
174 | domain_extra, | |||
|
175 | split_re, | |||
|
176 | normalize_name, | |||
|
177 | format_f): | |||
|
178 | """Update file with contributor information. | |||
|
179 | all_entries: list of tuples with year and name | |||
|
180 | no_entries: set of names or name and year tuples to ignore | |||
|
181 | domain_extra: map domain name to extra credit name | |||
|
182 | split_re: regexp matching the part of file to rewrite | |||
|
183 | normalize_name: function to normalize names for grouping and display | |||
|
184 | format_f: function formatting year list and name to a string | |||
|
185 | """ | |||
|
186 | name_years = defaultdict(set) | |||
|
187 | ||||
|
188 | for year, name in all_entries: | |||
|
189 | if name in no_entries or (name, year) in no_entries: | |||
|
190 | continue | |||
|
191 | domain = name.split('@', 1)[-1].rstrip('>') | |||
|
192 | if domain in domain_extra: | |||
|
193 | name_years[domain_extra[domain]].add(year) | |||
|
194 | name_years[normalize_name(name)].add(year) | |||
|
195 | ||||
|
196 | l = [(list(sorted(year for year in years if year)), name) | |||
|
197 | for name, years in name_years.items()] | |||
|
198 | l.sort(key=sortkey) | |||
|
199 | ||||
|
200 | with file(filename) as f: | |||
|
201 | pre, post = re.split(split_re, f.read()) | |||
|
202 | ||||
|
203 | with file(filename, 'w') as f: | |||
|
204 | f.write(pre + | |||
|
205 | ''.join(format_f(years, name) for years, name in l) + | |||
|
206 | post) | |||
|
207 | ||||
|
208 | ||||
|
209 | def main(): | |||
|
210 | repo_entries = [ | |||
|
211 | (year, name_fixes.get(name) or name_fixes.get(name.rsplit('<', 1)[0].strip()) or name) | |||
|
212 | for year, name in | |||
|
213 | (line.strip().split(' ', 1) | |||
|
214 | for line in os.popen("""hg log -r '::.' -T '{date(date,"%Y")} {author}\n'""").readlines()) | |||
|
215 | ] | |||
|
216 | ||||
|
217 | insert_entries( | |||
|
218 | filename='kallithea/templates/about.html', | |||
|
219 | all_entries=repo_entries + other_about, | |||
|
220 | no_entries=no_about, | |||
|
221 | domain_extra=domain_extra, | |||
|
222 | split_re=r'(?: <li>Copyright © [^\n]*</li>\n)*', | |||
|
223 | normalize_name=lambda name: name.split('<', 1)[0].strip(), | |||
|
224 | format_f=lambda years, name: ' <li>Copyright © %s, %s</li>\n' % (nice_years(years, '–', ', '), name), | |||
|
225 | ) | |||
|
226 | ||||
|
227 | insert_entries( | |||
|
228 | filename='CONTRIBUTORS', | |||
|
229 | all_entries=repo_entries + other_contributors, | |||
|
230 | no_entries=total_ignore, | |||
|
231 | domain_extra=domain_extra, | |||
|
232 | split_re=r'(?: [^\n]*\n)*', | |||
|
233 | normalize_name=lambda name: name, | |||
|
234 | format_f=lambda years, name: (' %s%s%s\n' % (name, ' ' if years else '', nice_years(years))), | |||
|
235 | ) | |||
|
236 | ||||
|
237 | insert_entries( | |||
|
238 | filename='kallithea/templates/base/base.html', | |||
|
239 | all_entries=repo_entries, | |||
|
240 | no_entries=total_ignore, | |||
|
241 | domain_extra={}, | |||
|
242 | split_re=r'(?<=©) .* (?=by various authors)', | |||
|
243 | normalize_name=lambda name: '', | |||
|
244 | format_f=lambda years, name: ' ' + nice_years(years, '–', ', ') + ' ', | |||
|
245 | ) | |||
|
246 | ||||
|
247 | ||||
|
248 | if __name__ == '__main__': | |||
|
249 | main() | |||
|
250 | ||||
|
251 | ||||
|
252 | # To list new contributors since last tagging: | |||
|
253 | # { hg log -r '::tagged()' -T ' {author}\n {author}\n'; hg log -r '::.' -T ' {author}\n' | sort | uniq; } | sort | uniq -u |
@@ -1,11 +1,19 b'' | |||||
1 | List of contributors to Kallithea project: |
|
1 | List of contributors to Kallithea project: | |
2 |
|
2 | |||
3 |
Mads Kiilerich <madski@unity3d.com> 2012-201 |
|
3 | Mads Kiilerich <madski@unity3d.com> 2012-2017 | |
|
4 | Unity Technologies 2012-2017 | |||
|
5 | Andrew Shadura <andrew@shadura.me> 2012 2014-2017 | |||
|
6 | Dominik Ruf <dominikruf@gmail.com> 2012 2014 2016-2017 | |||
|
7 | Sam Jaques <sam.jaques@me.com> 2015 2017 | |||
|
8 | Mads Kiilerich <mads@kiilerich.com> 2016-2017 | |||
|
9 | Ching-Chen Mao <mao@lins.fju.edu.tw> 2017 | |||
|
10 | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> 2017 | |||
|
11 | Viktar Vauchkevich <victorenator@gmail.com> 2017 | |||
4 | Takumi IINO <trot.thunder@gmail.com> 2012-2016 |
|
12 | Takumi IINO <trot.thunder@gmail.com> 2012-2016 | |
5 | Unity Technologies 2012-2016 |
|
13 | Thomas De Schampheleire <thomas.de.schampheleire@gmail.com> 2014-2016 | |
6 | Andrew Shadura <andrew@shadura.me> 2012 2014-2016 |
|
|||
7 | Dominik Ruf <dominikruf@gmail.com> 2012 2014 2016 |
|
|||
8 | Søren Løvborg <sorenl@unity3d.com> 2015-2016 |
|
14 | Søren Løvborg <sorenl@unity3d.com> 2015-2016 | |
|
15 | Anton Shestakov <av6@dwimlabs.net> 2016 | |||
|
16 | Brandon Jones <bjones14@gmail.com> 2016 | |||
9 | Konstantin Veretennicov <kveretennicov@gmail.com> 2016 |
|
17 | Konstantin Veretennicov <kveretennicov@gmail.com> 2016 | |
10 | Robert James Dennington <tinytimrob@googlemail.com> 2016 |
|
18 | Robert James Dennington <tinytimrob@googlemail.com> 2016 | |
11 | Aras Pranckevičius <aras@unity3d.com> 2012-2013 2015 |
|
19 | Aras Pranckevičius <aras@unity3d.com> 2012-2013 2015 | |
@@ -13,7 +21,6 b' List of contributors to Kallithea projec' | |||||
13 | Christian Oyarzun <oyarzun@gmail.com> 2014-2015 |
|
21 | Christian Oyarzun <oyarzun@gmail.com> 2014-2015 | |
14 | Joseph Rivera <rivera.d.joseph@gmail.com> 2014-2015 |
|
22 | Joseph Rivera <rivera.d.joseph@gmail.com> 2014-2015 | |
15 | Michal Čihař <michal@cihar.com> 2014-2015 |
|
23 | Michal Čihař <michal@cihar.com> 2014-2015 | |
16 | Thomas De Schampheleire <thomas.de.schampheleire@gmail.com> 2014-2015 |
|
|||
17 | Anatoly Bubenkov <bubenkoff@gmail.com> 2015 |
|
24 | Anatoly Bubenkov <bubenkoff@gmail.com> 2015 | |
18 | Andrew Bartlett <abartlet@catalyst.net.nz> 2015 |
|
25 | Andrew Bartlett <abartlet@catalyst.net.nz> 2015 | |
19 | Balázs Úr <urbalazs@gmail.com> 2015 |
|
26 | Balázs Úr <urbalazs@gmail.com> 2015 | |
@@ -42,7 +49,6 b' List of contributors to Kallithea projec' | |||||
42 | Robert Martinez <ntttq@inboxen.org> 2015 |
|
49 | Robert Martinez <ntttq@inboxen.org> 2015 | |
43 | Robert Rauch <mail@robertrauch.de> 2015 |
|
50 | Robert Rauch <mail@robertrauch.de> 2015 | |
44 | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> 2015 |
|
51 | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> 2015 | |
45 | Sam Jaques <sam.jaques@me.com> 2015 |
|
|||
46 | Tuux <tuxa@galaxie.eu.org> 2015 |
|
52 | Tuux <tuxa@galaxie.eu.org> 2015 | |
47 | Viktar Palstsiuk <vipals@gmail.com> 2015 |
|
53 | Viktar Palstsiuk <vipals@gmail.com> 2015 | |
48 | Bradley M. Kuhn <bkuhn@sfconservancy.org> 2014 |
|
54 | Bradley M. Kuhn <bkuhn@sfconservancy.org> 2014 |
@@ -27,12 +27,19 b'' | |||||
27 | necessarily limited to the following: |
|
27 | necessarily limited to the following: | |
28 | <ul style="margin: 0 0 0 50px;"> |
|
28 | <ul style="margin: 0 0 0 50px;"> | |
29 |
|
29 | |||
30 |
<li>Copyright © 2012–201 |
|
30 | <li>Copyright © 2012–2017, Mads Kiilerich</li> | |
|
31 | <li>Copyright © 2012–2017, Unity Technologies</li> | |||
|
32 | <li>Copyright © 2012, 2014–2017, Andrew Shadura</li> | |||
|
33 | <li>Copyright © 2012, 2014, 2016–2017, Dominik Ruf</li> | |||
|
34 | <li>Copyright © 2015, 2017, Sam Jaques</li> | |||
|
35 | <li>Copyright © 2017, Ching-Chen Mao</li> | |||
|
36 | <li>Copyright © 2017, FUJIWARA Katsunori</li> | |||
|
37 | <li>Copyright © 2017, Viktar Vauchkevich</li> | |||
31 | <li>Copyright © 2012–2016, Takumi IINO</li> |
|
38 | <li>Copyright © 2012–2016, Takumi IINO</li> | |
32 |
<li>Copyright © 201 |
|
39 | <li>Copyright © 2014–2016, Thomas De Schampheleire</li> | |
33 | <li>Copyright © 2012, 2014–2016, Andrew Shadura</li> |
|
|||
34 | <li>Copyright © 2012, 2014, 2016, Dominik Ruf</li> |
|
|||
35 | <li>Copyright © 2015–2016, Søren Løvborg</li> |
|
40 | <li>Copyright © 2015–2016, Søren Løvborg</li> | |
|
41 | <li>Copyright © 2016, Anton Shestakov</li> | |||
|
42 | <li>Copyright © 2016, Brandon Jones</li> | |||
36 | <li>Copyright © 2016, Konstantin Veretennicov</li> |
|
43 | <li>Copyright © 2016, Konstantin Veretennicov</li> | |
37 | <li>Copyright © 2016, Robert James Dennington</li> |
|
44 | <li>Copyright © 2016, Robert James Dennington</li> | |
38 | <li>Copyright © 2012–2013, 2015, Aras Pranckevičius</li> |
|
45 | <li>Copyright © 2012–2013, 2015, Aras Pranckevičius</li> | |
@@ -40,7 +47,6 b'' | |||||
40 | <li>Copyright © 2014–2015, Joseph Rivera</li> |
|
47 | <li>Copyright © 2014–2015, Joseph Rivera</li> | |
41 | <li>Copyright © 2014–2015, Michal Čihař</li> |
|
48 | <li>Copyright © 2014–2015, Michal Čihař</li> | |
42 | <li>Copyright © 2014–2015, Sean Farley</li> |
|
49 | <li>Copyright © 2014–2015, Sean Farley</li> | |
43 | <li>Copyright © 2014–2015, Thomas De Schampheleire</li> |
|
|||
44 | <li>Copyright © 2015, Anatoly Bubenkov</li> |
|
50 | <li>Copyright © 2015, Anatoly Bubenkov</li> | |
45 | <li>Copyright © 2015, Andrew Bartlett</li> |
|
51 | <li>Copyright © 2015, Andrew Bartlett</li> | |
46 | <li>Copyright © 2015, Balázs Úr</li> |
|
52 | <li>Copyright © 2015, Balázs Úr</li> | |
@@ -69,7 +75,6 b'' | |||||
69 | <li>Copyright © 2015, Robert Martinez</li> |
|
75 | <li>Copyright © 2015, Robert Martinez</li> | |
70 | <li>Copyright © 2015, Robert Rauch</li> |
|
76 | <li>Copyright © 2015, Robert Rauch</li> | |
71 | <li>Copyright © 2015, Ronny Pfannschmidt</li> |
|
77 | <li>Copyright © 2015, Ronny Pfannschmidt</li> | |
72 | <li>Copyright © 2015, Sam Jaques</li> |
|
|||
73 | <li>Copyright © 2015, Tuux</li> |
|
78 | <li>Copyright © 2015, Tuux</li> | |
74 | <li>Copyright © 2015, Viktar Palstsiuk</li> |
|
79 | <li>Copyright © 2015, Viktar Palstsiuk</li> | |
75 | <li>Copyright © 2014, Bradley M. Kuhn</li> |
|
80 | <li>Copyright © 2014, Bradley M. Kuhn</li> |
General Comments 0
You need to be logged in to leave comments.
Login now