# HG changeset patch
# User Mads Kiilerich
# Date 2017-07-27 03:02:37
# Node ID a48802bf7134e5270f48eb05e10ccd375366cba9
# Parent 84d8cff41282ae16ab0b935a635182a512ff87a8
# Parent 9b9258f5e2b235d05967c93fe890dd1910774a3e
Merge stable
diff --git a/.hgsigs b/.hgsigs
--- a/.hgsigs
+++ b/.hgsigs
@@ -1,3 +1,4 @@
9b3e9e242f5c97cc0c7657e5ac93dce7de61ca16 0 iQEcBAABAgAGBQJWDuAdAAoJEJ1bI/kYT6UUAlYH/ReCa7Im5tvy+ot5oAc7xey/O2rCVHp2h6i82tTWK/0i9EaS4DP+eTbAjV4WJA4qWF5DPenEJ3X9JhrTLNvGkR0f7lUqiFVMTJ472YlSsvIWg38gVFruzwk1cODRfq72o8ERYcRSfzrL4cDpIqjEd/vVVCV/gKVvPmzr4/FED/ZmS0X6T9gxWJo/eWSuLNAxHHtE/pCWDO3XEe+iOm+hHjkyz4Hn2r9/+ucrirnzycH6DnYO/kWvQzBnzgMjJm+1rLZ5cfU89V8zfhv6z0pd8CHZfpKGc2Z8EwVJq9LR+M4/76uDlYXx7IfZAxhRNqN6MC+yvPmDo3382dNr7Wkopi0=
9bf8eb837e785b6856ccfac264e977ce3ebe1535 0 iQEcBAABAgAGBQJW5XaVAAoJEJ1bI/kYT6UUbeMH/AsGg21jTc0tTT+228T+WfrfkbxrPkkULQF/Eo3ChlrhnFZ5B1y7ellSx6XGas7yKpqHHtNmrVwY3KBfUaYEljML/osEt1kvM6JGcd0vDbAW1uA2sdJR2AXmf32MjguFVhmYi9Lj79WYtgg241YGPe4dH0ompNFVqazNxCfmDBZijzSkF57FURMpV2e6+MyNq0txSo9Q82eALy0GAIX7NKQcxtynxG9ETzVzuVpeNE9MEZh0ObbUtPGezd55GXXcVqI8ZEurZwf6KHnd5M+5wxIZf84gM/k4QgQbRiIxNj4QfVmTZlVNSkC7PwSbF8twZPjlAprwldYvMi/c7ZVocEY=
a84d40e9481fcea4dafadee86b03f0dd401527d6 0 iQEcBAABAgAGBQJXJ4XhAAoJEJ1bI/kYT6UUKaIH/i33ZiT95pWF3pHEftgrZWvMwvz9tAuoHgf7ntkIUPnxfNteXKw8FiKcSQ9f8I41VyML+rqsnBBIfltJknfoqTV+9jNkHwc62OfcqQ3RbBDXQbcSi1CHn2ihJiZadqiKEyUw7JJqOMyWp+AWQyywcF/ea+pwXPJG5A2fd4vnBWHSxhD+6Ig1KipZNORzZY7fAec185M7NOZCZC+5qOLIkoQZaGq+D2Aipx5eZkpgFd4W+0LQY1ywMV5CiOY1OG0mry7l6NfIZvPY9Kiwg37G6ZUi8fhwVvn6Y8UACcAnWunBfKt9PWK0rAgNyJ9HDk/+3S5g6HcNKUb6YRTzEcLshIc=
+64ea7ea0923618a0c117acebb816a6f0d162bfdb 0 iQEvBAABCAAZBQJZeN4NEhxhbmRyZXdAc2hhZHVyYS5tZQAKCRCdWyP5GE+lFGi/CACBEWfdtZNumWz5LJ6yHbiceEDXZ+9aD44EU3J3VfbRwLeZhQ7J0WwBCFg0qPxh08O+TMaeRP4ur20hczyR6u8fwmIc9KDmNZHujlG0Q6GkNSMizyfJgf/MYJD+03q2Z0S4e9QdPfc746TBZKaqqauV0uVjtd7+m3L4R+Qh5shxBNxshqGGWtMtXpO9iojCJEqxde9RVm+w9NidKdCLGoDlVpJ42iFSrUMeWBnVUMRhOiz6XKUrIPEjUfWMFe0gOR55wZcF3tJo8XBqqqhecI69cmLmkv1xG92V+jC5gTC3STYTASJqXHKEp2cRvUGbHrFF9ODBvcYjj+VsY5r2aU1l
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -64,3 +64,4 @@ c6e32714336345403adf76abb6ebf9b8116fcdc7
9b3e9e242f5c97cc0c7657e5ac93dce7de61ca16 0.3
9bf8eb837e785b6856ccfac264e977ce3ebe1535 0.3.1
a84d40e9481fcea4dafadee86b03f0dd401527d6 0.3.2
+64ea7ea0923618a0c117acebb816a6f0d162bfdb 0.3.3
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,18 +1,30 @@
List of contributors to Kallithea project:
- Mads Kiilerich 2012-2016
+ Mads Kiilerich 2012-2017
+ Unity Technologies 2012-2017
+ Andrew Shadura 2012 2014-2017
+ Dominik Ruf 2012 2014-2017
+ Thomas De Schampheleire 2014-2017
+ Søren Løvborg 2015-2017
+ Sam Jaques 2015 2017
+ Asterios Dimitriou 2016-2017
+ Mads Kiilerich 2016-2017
+ Alessandro Molina 2017
+ Anton Schur 2017
+ Ching-Chen Mao 2017
+ Eivind Tagseth 2017
+ FUJIWARA Katsunori 2017
+ Karl Goetz 2017
+ Marko Semet 2017
+ Viktar Vauchkevich 2017
Takumi IINO 2012-2016
- Unity Technologies 2012-2016
- Andrew Shadura 2012 2014-2016
- Dominik Ruf 2012 2014-2016
- Thomas De Schampheleire 2014-2016
Étienne Gilli 2015-2016
Jan Heylen 2015-2016
Robert Martinez 2015-2016
Robert Rauch 2015-2016
- Søren Løvborg 2015-2016
Angel Ezquerra 2016
- Asterios Dimitriou 2016
+ Anton Shestakov 2016
+ Brandon Jones 2016
Kateryna Musina 2016
Konstantin Veretennicov 2016
Oscar Curero 2016
@@ -49,7 +61,6 @@ List of contributors to Kallithea projec
Niemand Jedermann 2015
Peter Vitt 2015
Ronny Pfannschmidt 2015
- Sam Jaques 2015
Tuux 2015
Viktar Palstsiuk 2015
Ante Ilic 2014
diff --git a/kallithea/templates/about.html b/kallithea/templates/about.html
--- a/kallithea/templates/about.html
+++ b/kallithea/templates/about.html
@@ -27,19 +27,30 @@
necessarily limited to the following:
- - Copyright © 2012–2016, Mads Kiilerich
+ - Copyright © 2012–2017, Mads Kiilerich
+ - Copyright © 2012–2017, Unity Technologies
+ - Copyright © 2012, 2014–2017, Andrew Shadura
+ - Copyright © 2012, 2014–2017, Dominik Ruf
+ - Copyright © 2014–2017, Thomas De Schampheleire
+ - Copyright © 2015–2017, Søren Løvborg
+ - Copyright © 2015, 2017, Sam Jaques
+ - Copyright © 2016–2017, Asterios Dimitriou
+ - Copyright © 2017, Alessandro Molina
+ - Copyright © 2017, Anton Schur
+ - Copyright © 2017, Ching-Chen Mao
+ - Copyright © 2017, Eivind Tagseth
+ - Copyright © 2017, FUJIWARA Katsunori
+ - Copyright © 2017, Karl Goetz
+ - Copyright © 2017, Marko Semet
+ - Copyright © 2017, Viktar Vauchkevich
- Copyright © 2012–2016, Takumi IINO
- - Copyright © 2012–2016, Unity Technologies
- - Copyright © 2012, 2014–2016, Andrew Shadura
- - Copyright © 2012, 2014–2016, Dominik Ruf
- - Copyright © 2014–2016, Thomas De Schampheleire
- Copyright © 2015–2016, Étienne Gilli
- Copyright © 2015–2016, Jan Heylen
- Copyright © 2015–2016, Robert Martinez
- Copyright © 2015–2016, Robert Rauch
- - Copyright © 2015–2016, Søren Løvborg
- Copyright © 2016, Angel Ezquerra
- - Copyright © 2016, Asterios Dimitriou
+ - Copyright © 2016, Anton Shestakov
+ - Copyright © 2016, Brandon Jones
- Copyright © 2016, Kateryna Musina
- Copyright © 2016, Konstantin Veretennicov
- Copyright © 2016, Oscar Curero
@@ -76,7 +87,6 @@
- Copyright © 2015, Niemand Jedermann
- Copyright © 2015, Peter Vitt
- Copyright © 2015, Ronny Pfannschmidt
- - Copyright © 2015, Sam Jaques
- Copyright © 2015, Tuux
- Copyright © 2015, Viktar Palstsiuk
- Copyright © 2014, Ante Ilic
diff --git a/scripts/update-copyrights.py b/scripts/update-copyrights.py
new file mode 100755
--- /dev/null
+++ b/scripts/update-copyrights.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+"""
+Kallithea script for maintaining contributor lists from version control
+history.
+
+This script and the data in it is a best effort attempt at reverse engineering
+previous attributions and correlate that with version control history while
+preserving all existing copyright statements and attribution. This script is
+processing and summarizing information found elsewhere - it is not by itself
+making any claims. Comments in the script are an attempt at reverse engineering
+possible explanations - they are not showing any intent or confirming it is
+correct.
+
+Three files are generated / modified by this script:
+
+kallithea/templates/about.html claims to show copyright holders, and the GPL
+license requires such existing "legal notices" to be preserved. We also try to
+keep it updated with copyright holders, but do not claim it is a correct list.
+
+CONTRIBUTORS has the purpose of giving credit where credit is due and list all
+the contributor names in the source.
+
+kallithea/templates/base/base.html contains the copyright years in the page
+footer.
+
+Both make a best effort of listing all copyright holders, but revision control
+history might be a better and more definitive source.
+
+Contributors are sorted "fairly" by copyright year and amount of
+contribution.
+
+New contributors are listed, without considering if the contribution contains
+copyrightable work.
+
+When the copyright might belong to a different legal entity than the
+contributor, the legal entity is given credit too.
+"""
+
+
+# Some committers are so wrong that it doesn't point at any contributor:
+total_ignore = set()
+total_ignore.add('*** failed to import extension hggit: No module named hggit')
+total_ignore.add('<>')
+
+# Normalize some committer names where people have contributed under different
+# names or email addresses:
+name_fixes = {}
+name_fixes['Andrew Shadura'] = "Andrew Shadura "
+name_fixes['aparkar'] = "Aparkar "
+name_fixes['Aras Pranckevicius'] = "Aras Pranckevičius "
+name_fixes['Augosto Hermann'] = "Augusto Herrmann "
+name_fixes['"Bradley M. Kuhn" '] = "Bradley M. Kuhn "
+name_fixes['dmitri.kuznetsov'] = "Dmitri Kuznetsov"
+name_fixes['Dmitri Kuznetsov'] = "Dmitri Kuznetsov"
+name_fixes['domruf'] = "Dominik Ruf "
+name_fixes['Ingo von borstel'] = "Ingo von Borstel "
+name_fixes['Jan Heylen'] = "Jan Heylen "
+name_fixes['Jason F. Harris'] = "Jason Harris "
+name_fixes['Jelmer Vernooij'] = "Jelmer Vernooij "
+name_fixes['jfh '] = "Jason Harris "
+name_fixes['Leonardo Carneiro'] = "Leonardo Carneiro "
+name_fixes['leonardo'] = "Leonardo Carneiro "
+name_fixes['Leonardo '] = "Leonardo Carneiro "
+name_fixes['Les Peabody'] = "Les Peabody "
+name_fixes['"Lorenzo M. Catucci" '] = "Lorenzo M. Catucci "
+name_fixes['Lukasz Balcerzak'] = "Łukasz Balcerzak "
+name_fixes['mao '] = "Ching-Chen Mao "
+name_fixes['marcink'] = "Marcin Kuźmiński "
+name_fixes['Marcin Kuzminski'] = "Marcin Kuźmiński "
+name_fixes['nansenat16@null.tw'] = "nansenat16 "
+name_fixes['Peter Vitt'] = "Peter Vitt "
+name_fixes['philip.j@hostdime.com'] = "Philip Jameson "
+name_fixes['Søren Løvborg'] = "Søren Løvborg "
+name_fixes['Thomas De Schampheleire'] = "Thomas De Schampheleire "
+name_fixes['Weblate'] = "<>"
+name_fixes['xpol'] = "xpol "
+
+
+# Some committer email address domains that indicate that another entity might
+# hold some copyright too:
+domain_extra = {}
+domain_extra['unity3d.com'] = "Unity Technologies"
+domain_extra['rhodecode.com'] = "RhodeCode GmbH"
+
+# Repository history show some old contributions that traditionally hasn't been
+# listed in about.html - preserve that:
+no_about = set(total_ignore)
+# The following contributors were traditionally not listed in about.html and it
+# seems unclear if the copyright is personal or belongs to a company.
+no_about.add(('Thayne Harbaugh ', '2011'))
+no_about.add(('Dies Koper ', '2012'))
+no_about.add(('Erwin Kroon ', '2012'))
+no_about.add(('Vincent Caron ', '2012'))
+# These contributors' contributions might be too small to be copyrightable:
+no_about.add(('philip.j@hostdime.com', '2012'))
+no_about.add(('Stefan Engel ', '2012'))
+no_about.add(('Ton Plomp ', '2013'))
+# Was reworked and contributed later and shadowed by other contributions:
+no_about.add(('Sean Farley ', '2013'))
+
+# Preserve contributors listed in about.html but not appearing in repository
+# history:
+other_about = [
+ ("2011", "Aparkar "),
+ ("2010", "RhodeCode GmbH"),
+ ("2011", "RhodeCode GmbH"),
+ ("2012", "RhodeCode GmbH"),
+ ("2013", "RhodeCode GmbH"),
+]
+
+# Preserve contributors listed in CONTRIBUTORS but not appearing in repository
+# history:
+other_contributors = [
+ ("", "Andrew Kesterson "),
+ ("", "cejones"),
+ ("", "David A. Sjøen "),
+ ("", "James Rhodes "),
+ ("", "Jonas Oberschweiber "),
+ ("", "larikale"),
+ ("", "RhodeCode GmbH"),
+ ("", "Sebastian Kreutzberger "),
+ ("", "Steve Romanow "),
+ ("", "SteveCohen"),
+ ("", "Thomas "),
+ ("", "Thomas Waldmann "),
+]
+
+
+import os
+import re
+from collections import defaultdict
+
+
+def sortkey(x):
+ """Return key for sorting contributors "fairly":
+ * latest contribution
+ * first contribution
+ * number of contribution years
+ * name (with some unicode normalization)
+ The entries must be 2-tuples of a list of string years and the unicode name"""
+ return (x[0] and -int(x[0][-1]),
+ x[0] and int(x[0][0]),
+ -len(x[0]),
+ x[1].decode('utf8').lower().replace(u'\xe9', u'e').replace(u'\u0142', u'l')
+ )
+
+
+def nice_years(l, dash='-', join=' '):
+ """Convert a list of years into brief range like '1900-1901, 1921'."""
+ if not l:
+ return ''
+ start = end = int(l[0])
+ ranges = []
+ for year in l[1:] + [0]:
+ year = int(year)
+ if year == end + 1:
+ end = year
+ continue
+ if start == end:
+ ranges.append('%s' % start)
+ else:
+ ranges.append('%s%s%s' % (start, dash, end))
+ start = end = year
+ assert start == 0 and end == 0, (start, end)
+ return join.join(ranges)
+
+
+def insert_entries(
+ filename,
+ all_entries,
+ no_entries,
+ domain_extra,
+ split_re,
+ normalize_name,
+ format_f):
+ """Update file with contributor information.
+ all_entries: list of tuples with year and name
+ no_entries: set of names or name and year tuples to ignore
+ domain_extra: map domain name to extra credit name
+ split_re: regexp matching the part of file to rewrite
+ normalize_name: function to normalize names for grouping and display
+ format_f: function formatting year list and name to a string
+ """
+ name_years = defaultdict(set)
+
+ for year, name in all_entries:
+ if name in no_entries or (name, year) in no_entries:
+ continue
+ domain = name.split('@', 1)[-1].rstrip('>')
+ if domain in domain_extra:
+ name_years[domain_extra[domain]].add(year)
+ name_years[normalize_name(name)].add(year)
+
+ l = [(list(sorted(year for year in years if year)), name)
+ for name, years in name_years.items()]
+ l.sort(key=sortkey)
+
+ with file(filename) as f:
+ pre, post = re.split(split_re, f.read())
+
+ with file(filename, 'w') as f:
+ f.write(pre +
+ ''.join(format_f(years, name) for years, name in l) +
+ post)
+
+
+def main():
+ repo_entries = [
+ (year, name_fixes.get(name) or name_fixes.get(name.rsplit('<', 1)[0].strip()) or name)
+ for year, name in
+ (line.strip().split(' ', 1)
+ for line in os.popen("""hg log -r '::.' -T '{date(date,"%Y")} {author}\n'""").readlines())
+ ]
+
+ insert_entries(
+ filename='kallithea/templates/about.html',
+ all_entries=repo_entries + other_about,
+ no_entries=no_about,
+ domain_extra=domain_extra,
+ split_re=r'(?: - Copyright © [^\n]*
\n)*',
+ normalize_name=lambda name: name.split('<', 1)[0].strip(),
+ format_f=lambda years, name: ' - Copyright © %s, %s
\n' % (nice_years(years, '–', ', '), name),
+ )
+
+ insert_entries(
+ filename='CONTRIBUTORS',
+ all_entries=repo_entries + other_contributors,
+ no_entries=total_ignore,
+ domain_extra=domain_extra,
+ split_re=r'(?: [^\n]*\n)*',
+ normalize_name=lambda name: name,
+ format_f=lambda years, name: (' %s%s%s\n' % (name, ' ' if years else '', nice_years(years))),
+ )
+
+ insert_entries(
+ filename='kallithea/templates/base/base.html',
+ all_entries=repo_entries,
+ no_entries=total_ignore,
+ domain_extra={},
+ split_re=r'(?<=©) .* (?=by various authors)',
+ normalize_name=lambda name: '',
+ format_f=lambda years, name: ' ' + nice_years(years, '–', ', ') + ' ',
+ )
+
+
+if __name__ == '__main__':
+ main()
+
+
+# To list new contributors since last tagging:
+# { hg log -r '::tagged()' -T ' {author}\n {author}\n'; hg log -r '::.' -T ' {author}\n' | sort | uniq; } | sort | uniq -u