#!/usr/bin/env python3 # # InspIRCd -- Internet Relay Chat Daemon # # Copyright (C) 2026 Sadie Powell # # This file is part of InspIRCd. InspIRCd is free software: you can # redistribute it and/or modify it under the terms of the GNU General Public # License as published by the Free Software Foundation, version 2. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import os import re import shutil import subprocess import sys import textwrap import columnize import yaml CC_RED = "\x1B[1;31m" if sys.stdout.isatty() else "" CC_RESET = "\x1B[0m" if sys.stdout.isatty() else "" ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) GIT = os.getenv("GIT", "git") if not shutil.which(GIT): print( f"{CC_RED}Error:{CC_RESET} Git ({GIT}) must be installed to build the author list!", file=sys.stderr, ) commit_log = subprocess.check_output( [GIT, "log", "--pretty=%an <%ae>%n%(trailers:key=Co-Authored-By,valueonly)", "HEAD"] ).split(b"\n") committers = {} for committer in [c for c in commit_log if c]: committers[committer] = committers.get(committer, 0) + 1 authors = {} for committer, commits in committers.items(): author = ( subprocess.check_output([GIT, "check-mailmap", committer]) .strip() .decode("utf-8") ) # Remove email addresses that aren"t real. author = re.sub( r"^(.+) <(?:unknown@email.invalid|\S+@users.noreply.github.com)>$", r"\1", author, ) # Skip GitHub bots like dependabot. if author.endswith("[bot]"): continue # Skip commits made by our own scripts. if author == "InspIRCd Robot ": continue authors[author] = authors.get(author, 0) + commits authors_txt = os.path.join(ROOT, "docs", "AUTHORS.txt") with open(authors_txt, "w") as fh: print( textwrap.dedent( f""" Since the first commit in January 2003 {len(authors)} people have submitted patches, commits, and other useful contributions to InspIRCd. These people, ordered by the number of contributions they have made, are: """ ).lstrip(), file=fh, ) # We show the names in the authors file ordered by number of commits and # then name case insensitively. sorted_authors = list(authors.items()) sorted_authors.sort(key=lambda a: a[0].lower()) sorted_authors.sort(key=lambda a: a[1], reverse=True) for author, commits in sorted_authors: print(f" * {author}", file=fh) info_h = os.path.join(ROOT, "modules", "core", "core_info", "info.h") with open(info_h, "w") as ofh: print( textwrap.dedent( """ // This file was generated by mkauthors. Any changes will be overwritten. #pragma once static constexpr const char* const lines[] = { \t" _____ _____ _____ _____ _ ", \t"|_ _| |_ _| | __ \\\\ / ____| | |", \t" | | _ __ ___ _ __ | | | |__) || | __| |", \t" | | | '_ \\\\ / __| | '_ \\\\ | | | _ / | | / _` |", \t" _| |_ | | | | \\\\__ \\\\ | |_) | _| |_ | | \\\\ \\\\ | |____ | (_| |", \t"|_____| |_| |_| |___/ | .__/ |_____| |_| \\\\_\\\\ \\\\_____| \\\\__,_|", \t" _____________________| |__________________________________ ", \t"|_____________________|_|__________________________________|", """ ).strip(), file=ofh, ) info_yml = os.path.join(ROOT, "modules", "core", "core_info", "info.yml") with open(info_yml, "r") as ifh: seen = [] for team, members in yaml.safe_load(ifh).items(): print(f'\t" ",\n\t"\\002{team}\\002:",', file=ofh) names = [] if isinstance(members, list): for member in members: if "name" in member: names.append(f"{member["name"]} ({member["nick"]})") seen.append(member["name"]) else: names.append(member["nick"]) else: for author in authors: name = re.sub(r"^(.+) <.+>$", r"\1", author) if name not in seen: names.append(name) names.sort(key=lambda n: n.lower()) lines = ( columnize.columnize( names, arrange_vertical=False, colsep=" " * 4, displaywidth=78 ) .strip() .split("\n") ) for line in lines: print(f'\t" {line}",', file=ofh) print( textwrap.dedent( """ \t"", \t"For more information visit https://www.inspircd.org/ or our IRC channel at", \t"ircs://irc.teranova.net/inspircd.", \tnullptr, }; """ ).strip(), file=ofh, ) if int(os.getenv("MKAUTHORS_COMMIT", "1")) > 0: subprocess.check_call( [ GIT, "commit", "--author", "InspIRCd Robot ", "--message", "Update the author list.", "--", authors_txt, info_h, ] )