This commit implements described in the #104573. The goal is to fix the confusion of the submodule hashes change, which are not ideal for any of the supported git-module configuration (they are either always visible causing confusion, or silently staged and committed, also causing confusion). This commit replaces submodules with a checkout of addons and addons_contrib, covered by the .gitignore, and locale and developer tools are moved to the main repository. This also changes the paths: - /release/scripts are moved to the /scripts - /source/tools are moved to the /tools - /release/datafiles/locale is moved to /locale This is done to avoid conflicts when using bisect, and also allow buildbot to automatically "recover" wgen building older or newer branches/patches. Running `make update` will initialize the local checkout to the changed repository configuration. Another aspect of the change is that the make update will support Github style of remote organization (origin remote pointing to thy fork, upstream remote pointing to the upstream blender/blender.git). Pull Request #104755
264 lines
8.4 KiB
Python
Executable File
264 lines
8.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
||
"""
|
||
Example use:
|
||
|
||
credits_git_gen.py --source=/src/blender --range=SHA1..HEAD
|
||
"""
|
||
|
||
from git_log import GitCommitIter
|
||
import unicodedata as ud
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# Lookup Table to clean up the credits
|
||
#
|
||
# This is a combination of unifying git logs as well as
|
||
# name change requested by the authors.
|
||
|
||
author_table = {
|
||
"Aaron": "Aaron Carlisle",
|
||
"Your Name": "Aaron Carlisle",
|
||
"Alan": "Alan Troth",
|
||
"andreas atteneder": "Andreas Atteneder",
|
||
"Ankit": "Ankit Meel",
|
||
"Antonioya": "Antonio Vazquez",
|
||
"Antonio Vazquez": "Antonio Vazquez",
|
||
"Antony Ryakiotakis": "Antony Riakiotakis",
|
||
"Amélie Fondevilla": "Amelie Fondevilla",
|
||
"bastien": "Bastien Montagne",
|
||
"mont29": "Bastien Montagne",
|
||
"bjornmose": "Bjorn Mose",
|
||
"meta-androcto": "Brendon Murphy",
|
||
"Brecht van Lommel": "Brecht Van Lommel",
|
||
"Brecht Van Lömmel": "Brecht Van Lommel",
|
||
"recht Van Lommel": "Brecht Van Lommel",
|
||
"Clément Foucault": "Clément Foucault",
|
||
"Clément": "Clément Foucault",
|
||
"fclem": "Clément Foucault",
|
||
"Clment Foucault": "Clément Foucault",
|
||
"christian brinkmann": "Christian Brinkmann",
|
||
"ZanQdo": "Daniel Salazar",
|
||
"unclezeiv": "Davide Vercelli",
|
||
"dilithjay": "Dilith Jayakody",
|
||
"gaiaclary": "Gaia Clary",
|
||
"Diego Hernan Borghetti": "Diego Borghetti",
|
||
"Dotsnov Valentin": "Dontsov Valentin",
|
||
"Eitan": "Eitan Traurig",
|
||
"EitanSomething": "Eitan Traurig",
|
||
"Erik": "Erik Abrahamsson",
|
||
"Erick Abrahammson": "Erik Abrahamsson",
|
||
"Eric Abrahamsson": "Erik Abrahamsson",
|
||
"Ethan-Hall": "Ethan Hall",
|
||
"filedescriptor": "Falk David",
|
||
"Germano": "Germano Cavalcante",
|
||
"Germano Cavalcantemano-wii": "Germano Cavalcante",
|
||
"mano-wii": "Germano Cavalcante",
|
||
"gsr": "Guillermo S. Romero",
|
||
"Henrik Dick (weasel)": "Henrik Dick",
|
||
"howardt": "Howard Trickey",
|
||
"Iliay Katueshenock": "Iliya Katueshenock",
|
||
"MOD": "Iliya Katueshenock",
|
||
"Inês Almeida": "Ines Almeida",
|
||
"brita": "Ines Almeida",
|
||
"Ivan": "Ivan Perevala",
|
||
"jensverwiebe": "Jens Verwiebe",
|
||
"Jesse Y": "Jesse Yurkovich",
|
||
"Joe Eagar": "Joseph Eagar",
|
||
"Johnny Matthews (guitargeek)": "Johnny Matthews",
|
||
"guitargeek": "Johnny Matthews",
|
||
"jon denning": "Jon Denning",
|
||
"julianeisel": "Julian Eisel",
|
||
"Severin": "Julian Eisel",
|
||
"Alex Strand": "Kenzie Strand",
|
||
"Kevin Dietrich": "Kévin Dietrich",
|
||
"Leon Leno": "Leon Schittek",
|
||
"Lukas Toenne": "Lukas Tönne",
|
||
"Mikhail": "Mikhail Matrosov",
|
||
"OmarSquircleArt": "Omar Emara",
|
||
"lazydodo": "Ray Molenkamp",
|
||
"Ray molenkamp": "Ray Molenkamp",
|
||
"Author Name": "Robert Guetzkow",
|
||
"Sybren A. Stüvel": "Sybren A. Stüvel",
|
||
"Simon": "Simon G",
|
||
"Stephan": "Stephan Seitz",
|
||
"Sebastian Herhoz": "Sebastian Herholz",
|
||
"blender": "Sergey Sharybin",
|
||
"Vuk GardaÅ¡eviÄ": "Vuk Gardašević",
|
||
"ianwill": "Willian Padovani Germano",
|
||
"Yiming Wu": "YimingWu",
|
||
}
|
||
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# Class for generating credits
|
||
|
||
class CreditUser:
|
||
__slots__ = (
|
||
"commit_total",
|
||
"year_min",
|
||
"year_max",
|
||
)
|
||
|
||
def __init__(self):
|
||
self.commit_total = 0
|
||
|
||
|
||
class Credits:
|
||
__slots__ = (
|
||
"users",
|
||
)
|
||
|
||
def __init__(self):
|
||
self.users = {}
|
||
|
||
def process_commit(self, c):
|
||
# Normalize author string into canonical form, prevents duplicate credit users
|
||
author = ud.normalize('NFC', c.author)
|
||
author = author_table.get(author, author)
|
||
year = c.date.year
|
||
cu = self.users.get(author)
|
||
if cu is None:
|
||
cu = self.users[author] = CreditUser()
|
||
cu.year_min = year
|
||
cu.year_max = year
|
||
|
||
cu.commit_total += 1
|
||
cu.year_min = min(cu.year_min, year)
|
||
cu.year_max = max(cu.year_max, year)
|
||
|
||
def process(self, commit_iter):
|
||
for i, c in enumerate(commit_iter):
|
||
self.process_commit(c)
|
||
if not (i % 100):
|
||
print(i)
|
||
|
||
def write(self, filepath,
|
||
is_main_credits=True,
|
||
contrib_companies=(),
|
||
sort="name"):
|
||
|
||
# patch_word = "patch", "patches"
|
||
commit_word = "commit", "commits"
|
||
|
||
sorted_authors = {}
|
||
if sort == "commit":
|
||
sorted_authors = dict(sorted(self.users.items(), key=lambda item: item[1].commit_total))
|
||
else:
|
||
sorted_authors = dict(sorted(self.users.items()))
|
||
|
||
with open(filepath, 'w', encoding="ascii", errors='xmlcharrefreplace') as file:
|
||
file.write("<h3>Individual Contributors</h3>\n\n")
|
||
for author, cu in sorted_authors.items():
|
||
file.write("{:s}, {:,d} {:s} {:s}<br />\n".format(
|
||
author,
|
||
cu.commit_total,
|
||
commit_word[cu.commit_total > 1],
|
||
("" if not is_main_credits else
|
||
("- {:d}".format(cu.year_min) if cu.year_min == cu.year_max else
|
||
("({:d} - {:d})".format(cu.year_min, cu.year_max))))))
|
||
file.write("\n\n")
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Companies, hard coded
|
||
if is_main_credits:
|
||
file.write("<h3>Contributions from Companies & Organizations</h3>\n")
|
||
file.write("<p>\n")
|
||
for line in contrib_companies:
|
||
file.write("{:s}<br />\n".format(line))
|
||
file.write("</p>\n")
|
||
|
||
import datetime
|
||
now = datetime.datetime.now()
|
||
fn = __file__.split("\\")[-1].split("/")[-1]
|
||
file.write(
|
||
"<p><center><i>Generated by '{:s}' {:d}/{:d}/{:d}</i></center></p>\n".format(
|
||
fn, now.year, now.month, now.day
|
||
))
|
||
|
||
|
||
def argparse_create():
|
||
import argparse
|
||
|
||
# When --help or no args are given, print this help
|
||
usage_text = "Review revisions."
|
||
|
||
epilog = "This script is used to generate credits"
|
||
|
||
parser = argparse.ArgumentParser(description=usage_text, epilog=epilog)
|
||
|
||
parser.add_argument(
|
||
"--source", dest="source_dir",
|
||
metavar='PATH',
|
||
required=True,
|
||
help="Path to git repository",
|
||
)
|
||
parser.add_argument(
|
||
"--range",
|
||
dest="range_sha1",
|
||
metavar='SHA1_RANGE',
|
||
required=True,
|
||
help="Range to use, eg: 169c95b8..HEAD",
|
||
)
|
||
|
||
parser.add_argument(
|
||
"--sort", dest="sort",
|
||
metavar='METHOD',
|
||
required=False,
|
||
help="Sort credits by 'name' (default) or 'commit'",
|
||
)
|
||
|
||
return parser
|
||
|
||
|
||
def main():
|
||
|
||
# ----------
|
||
# Parse Args
|
||
|
||
args = argparse_create().parse_args()
|
||
|
||
def is_credit_commit_valid(c):
|
||
ignore_dir = (
|
||
b"blender/extern/",
|
||
b"blender/intern/opennl/",
|
||
)
|
||
|
||
if not any(f for f in c.files if not f.startswith(ignore_dir)):
|
||
return False
|
||
|
||
return True
|
||
|
||
# TODO, there are for sure more companies then are currently listed.
|
||
# 1 liners for in html syntax
|
||
contrib_companies = (
|
||
"<b>Unity Technologies</b> - FBX Exporter",
|
||
"<b>BioSkill GmbH</b> - H3D compatibility for X3D Exporter, "
|
||
"OBJ Nurbs Import/Export",
|
||
"<b>AutoCRC</b> - Improvements to fluid particles, vertex color baking",
|
||
"<b>Adidas</b> - Principled BSDF shader in Cycles",
|
||
"<b>AMD</b> - Cycles HIP GPU rendering, CPU optimizations",
|
||
"<b>Intel</b> - Cycles oneAPI GPU rendering, CPU optimizations",
|
||
"<b>NVIDIA</b> - Cycles OptiX GPU rendering, USD importer",
|
||
"<b>Facebook</b> - Cycles subsurface scattering improvements",
|
||
"<b>Apple</b> - Cycles Metal GPU backend",
|
||
)
|
||
|
||
credits = Credits()
|
||
# commit_range = "HEAD~10..HEAD"
|
||
# commit_range = "blender-v2.81-release..blender-v2.82-release"
|
||
# commit_range = "blender-v2.82-release"
|
||
commit_range = args.range_sha1
|
||
sort = args.sort
|
||
citer = GitCommitIter(args.source_dir, commit_range)
|
||
credits.process((c for c in citer if is_credit_commit_valid(c)))
|
||
credits.write("credits.html",
|
||
is_main_credits=True,
|
||
contrib_companies=contrib_companies,
|
||
sort=sort)
|
||
print("Written: credits.html")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|