##// END OF EJS Templates
scripts: prepare for giving credit for contributions that have been integrated into other changesets
Mads Kiilerich -
r7661:a44228cd default
parent child Browse files
Show More
@@ -1,90 +1,96 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Some committers are so wrong that it doesn't point at any contributor:
4 4 total_ignore = set()
5 5 total_ignore.add('*** failed to import extension hggit: No module named hggit')
6 6 total_ignore.add('<>')
7 7
8 8 # Normalize some committer names where people have contributed under different
9 9 # names or email addresses:
10 10 name_fixes = {}
11 11 name_fixes['Andrew Shadura'] = "Andrej Shadura <andrew@shadura.me>"
12 12 name_fixes['aparkar'] = "Aparkar <aparkar@icloud.com>"
13 13 name_fixes['Aras Pranckevicius'] = "Aras Pranckevičius <aras@unity3d.com>"
14 14 name_fixes['Augosto Hermann'] = "Augusto Herrmann <augusto.herrmann@planejamento.gov.br>"
15 15 name_fixes['"Bradley M. Kuhn" <bkuhn@ebb.org>'] = "Bradley M. Kuhn <bkuhn@sfconservancy.org>"
16 16 name_fixes['dmitri.kuznetsov'] = "Dmitri Kuznetsov"
17 17 name_fixes['Dmitri Kuznetsov'] = "Dmitri Kuznetsov"
18 18 name_fixes['domruf'] = "Dominik Ruf <dominikruf@gmail.com>"
19 19 name_fixes['Ingo von borstel'] = "Ingo von Borstel <kallithea@planetmaker.de>"
20 20 name_fixes['Jan Heylen'] = "Jan Heylen <heyleke@gmail.com>"
21 21 name_fixes['Jason F. Harris'] = "Jason Harris <jason@jasonfharris.com>"
22 22 name_fixes['Jelmer Vernooij'] = "Jelmer VernooΔ³ <jelmer@samba.org>"
23 23 name_fixes['jfh <jason@jasonfharris.com>'] = "Jason Harris <jason@jasonfharris.com>"
24 24 name_fixes['Leonardo Carneiro<leonardo@unity3d.com>'] = "Leonardo Carneiro <leonardo@unity3d.com>"
25 25 name_fixes['leonardo'] = "Leonardo Carneiro <leonardo@unity3d.com>"
26 26 name_fixes['Leonardo <leo@unity3d.com>'] = "Leonardo Carneiro <leonardo@unity3d.com>"
27 27 name_fixes['Les Peabody'] = "Les Peabody <lpeabody@gmail.com>"
28 28 name_fixes['"Lorenzo M. Catucci" <lorenzo@sancho.ccd.uniroma2.it>'] = "Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>"
29 29 name_fixes['Lukasz Balcerzak'] = "Łukasz Balcerzak <lukaszbalcerzak@gmail.com>"
30 30 name_fixes['mao <mao@lins.fju.edu.tw>'] = "Ching-Chen Mao <mao@lins.fju.edu.tw>"
31 31 name_fixes['marcink'] = "Marcin KuΕΊmiΕ„ski <marcin@python-works.com>"
32 32 name_fixes['Marcin Kuzminski'] = "Marcin KuΕΊmiΕ„ski <marcin@python-works.com>"
33 33 name_fixes['nansenat16@null.tw'] = "nansenat16 <nansenat16@null.tw>"
34 34 name_fixes['Peter Vitt'] = "Peter Vitt <petervitt@web.de>"
35 35 name_fixes['philip.j@hostdime.com'] = "Philip Jameson <philip.j@hostdime.com>"
36 36 name_fixes['SΓΈren LΓΈvborg'] = "SΓΈren LΓΈvborg <sorenl@unity3d.com>"
37 37 name_fixes['Thomas De Schampheleire'] = "Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>"
38 38 name_fixes['Hosted Weblate'] = "<>"
39 39 name_fixes['Weblate'] = "<>"
40 40 name_fixes['xpol'] = "xpol <xpolife@gmail.com>"
41 41 name_fixes['Lars <devel@sumpfralle.de>'] = "Lars Kruse <devel@sumpfralle.de>"
42 42
43 43 # Some committer email address domains that indicate that another entity might
44 44 # hold some copyright too:
45 45 domain_extra = {}
46 46 domain_extra['unity3d.com'] = "Unity Technologies"
47 47 domain_extra['rhodecode.com'] = "RhodeCode GmbH"
48 48
49 49 # Repository history show some old contributions that traditionally hasn't been
50 50 # listed in about.html - preserve that:
51 51 no_about = set(total_ignore)
52 52 # The following contributors were traditionally not listed in about.html and it
53 53 # seems unclear if the copyright is personal or belongs to a company.
54 54 no_about.add(('Thayne Harbaugh <thayne@fusionio.com>', '2011'))
55 55 no_about.add(('Dies Koper <diesk@fast.au.fujitsu.com>', '2012'))
56 56 no_about.add(('Erwin Kroon <e.kroon@smartmetersolutions.nl>', '2012'))
57 57 no_about.add(('Vincent Caron <vcaron@bearstech.com>', '2012'))
58 58 # These contributors' contributions might be too small to be copyrightable:
59 59 no_about.add(('philip.j@hostdime.com', '2012'))
60 60 no_about.add(('Stefan Engel <mail@engel-stefan.de>', '2012'))
61 61 no_about.add(('Ton Plomp <tcplomp@gmail.com>', '2013'))
62 62 # Was reworked and contributed later and shadowed by other contributions:
63 63 no_about.add(('Sean Farley <sean.michael.farley@gmail.com>', '2013'))
64 64
65 # Contributors in about.html and CONTRIBUTORS not appearing in repository
66 # history:
67 other = [
68 # Work folded into commits attributed to others:
69 ]
70
65 71 # Preserve contributors listed in about.html but not appearing in repository
66 72 # history:
67 73 other_about = [
68 74 ("2011", "Aparkar <aparkar@icloud.com>"),
69 75 ("2010", "RhodeCode GmbH"),
70 76 ("2011", "RhodeCode GmbH"),
71 77 ("2012", "RhodeCode GmbH"),
72 78 ("2013", "RhodeCode GmbH"),
73 79 ]
74 80
75 81 # Preserve contributors listed in CONTRIBUTORS but not appearing in repository
76 82 # history:
77 83 other_contributors = [
78 84 ("", "Andrew Kesterson <andrew@aklabs.net>"),
79 85 ("", "cejones"),
80 86 ("", "David A. SjΓΈen <david.sjoen@westcon.no>"),
81 87 ("", "James Rhodes <jrhodes@redpointsoftware.com.au>"),
82 88 ("", "Jonas Oberschweiber <jonas.oberschweiber@d-velop.de>"),
83 89 ("", "larikale"),
84 90 ("", "RhodeCode GmbH"),
85 91 ("", "Sebastian Kreutzberger <sebastian@rhodecode.com>"),
86 92 ("", "Steve Romanow <slestak989@gmail.com>"),
87 93 ("", "SteveCohen"),
88 94 ("", "Thomas <thomas@rhodecode.com>"),
89 95 ("", "Thomas Waldmann <tw-public@gmx.de>"),
90 96 ]
@@ -1,164 +1,164 b''
1 1 #!/usr/bin/env python2
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 import contributor_data
45 45
46 46
47 47 def sortkey(x):
48 48 """Return key for sorting contributors "fairly":
49 49 * latest contribution
50 50 * first contribution
51 51 * number of contribution years
52 52 * name (with some unicode normalization)
53 53 The entries must be 2-tuples of a list of string years and the unicode name"""
54 54 return (x[0] and -int(x[0][-1]),
55 55 x[0] and int(x[0][0]),
56 56 -len(x[0]),
57 57 x[1].decode('utf-8').lower().replace(u'\xe9', u'e').replace(u'\u0142', u'l')
58 58 )
59 59
60 60
61 61 def nice_years(l, dash='-', join=' '):
62 62 """Convert a list of years into brief range like '1900-1901, 1921'."""
63 63 if not l:
64 64 return ''
65 65 start = end = int(l[0])
66 66 ranges = []
67 67 for year in l[1:] + [0]:
68 68 year = int(year)
69 69 if year == end + 1:
70 70 end = year
71 71 continue
72 72 if start == end:
73 73 ranges.append('%s' % start)
74 74 else:
75 75 ranges.append('%s%s%s' % (start, dash, end))
76 76 start = end = year
77 77 assert start == 0 and end == 0, (start, end)
78 78 return join.join(ranges)
79 79
80 80
81 81 def insert_entries(
82 82 filename,
83 83 all_entries,
84 84 no_entries,
85 85 domain_extra,
86 86 split_re,
87 87 normalize_name,
88 88 format_f):
89 89 """Update file with contributor information.
90 90 all_entries: list of tuples with year and name
91 91 no_entries: set of names or name and year tuples to ignore
92 92 domain_extra: map domain name to extra credit name
93 93 split_re: regexp matching the part of file to rewrite
94 94 normalize_name: function to normalize names for grouping and display
95 95 format_f: function formatting year list and name to a string
96 96 """
97 97 name_years = defaultdict(set)
98 98
99 99 for year, name in all_entries:
100 100 if name in no_entries or (name, year) in no_entries:
101 101 continue
102 102 domain = name.split('@', 1)[-1].rstrip('>')
103 103 if domain in domain_extra:
104 104 name_years[domain_extra[domain]].add(year)
105 105 name_years[normalize_name(name)].add(year)
106 106
107 107 l = [(list(sorted(year for year in years if year)), name)
108 108 for name, years in name_years.items()]
109 109 l.sort(key=sortkey)
110 110
111 111 with open(filename) as f:
112 112 pre, post = re.split(split_re, f.read())
113 113
114 114 with open(filename, 'w') as f:
115 115 f.write(pre +
116 116 ''.join(format_f(years, name) for years, name in l) +
117 117 post)
118 118
119 119
120 120 def main():
121 121 repo_entries = [
122 122 (year, contributor_data.name_fixes.get(name) or contributor_data.name_fixes.get(name.rsplit('<', 1)[0].strip()) or name)
123 123 for year, name in
124 124 (line.strip().split(' ', 1)
125 125 for line in os.popen("""hg log -r '::.' -T '{date(date,"%Y")} {author}\n'""").readlines())
126 126 ]
127 127
128 128 insert_entries(
129 129 filename='kallithea/templates/about.html',
130 all_entries=repo_entries + contributor_data.other_about,
130 all_entries=repo_entries + contributor_data.other_about + contributor_data.other,
131 131 no_entries=contributor_data.no_about,
132 132 domain_extra=contributor_data.domain_extra,
133 133 split_re=r'(?: <li>Copyright &copy; [^\n]*</li>\n)*',
134 134 normalize_name=lambda name: name.split('<', 1)[0].strip(),
135 135 format_f=lambda years, name: ' <li>Copyright &copy; %s, %s</li>\n' % (nice_years(years, '&ndash;', ', '), name),
136 136 )
137 137
138 138 insert_entries(
139 139 filename='CONTRIBUTORS',
140 all_entries=repo_entries + contributor_data.other_contributors,
140 all_entries=repo_entries + contributor_data.other_contributors + contributor_data.other,
141 141 no_entries=contributor_data.total_ignore,
142 142 domain_extra=contributor_data.domain_extra,
143 143 split_re=r'(?: [^\n]*\n)*',
144 144 normalize_name=lambda name: name,
145 145 format_f=lambda years, name: (' %s%s%s\n' % (name, ' ' if years else '', nice_years(years))),
146 146 )
147 147
148 148 insert_entries(
149 149 filename='kallithea/templates/base/base.html',
150 150 all_entries=repo_entries,
151 151 no_entries=contributor_data.total_ignore,
152 152 domain_extra={},
153 153 split_re=r'(?<=&copy;) .* (?=by various authors)',
154 154 normalize_name=lambda name: '',
155 155 format_f=lambda years, name: ' ' + nice_years(years, '&ndash;', ', ') + ' ',
156 156 )
157 157
158 158
159 159 if __name__ == '__main__':
160 160 main()
161 161
162 162
163 163 # To list new contributors since last tagging:
164 164 # { 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