#!/usr/bin/env python3
#
# InspIRCd -- Internet Relay Chat Daemon
#
# Copyright (C) 2026 Sadie Powell <sadie@witchery.services>
#
# 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 <http://www.gnu.org/licenses/>.
#
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 <noreply@inspircd.org>":
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 <noreply@inspircd.org>",
"--message", "Update the author list.",
"--",
authors_txt,
info_h,
]
)