#!/usr/bin/env python3 import os import re import subprocess import sys def get_author_display(author_name): if author_name == 'ScreamingHawk': return 'Michael Standen' else: return author_name def get_git_authors(file_path): """ Returns a list of unique author display-names for `file_path`, ordered by the timestamp of their first commit (oldest → newest). """ try: # Get lines like "Alice|1610000000" raw = subprocess.check_output( ['git', 'log', '--format=%aN|%at', '--', file_path], stderr=subprocess.DEVNULL ).decode('utf-8') except subprocess.CalledProcessError: return [] first_commit_ts = {} for line in raw.splitlines(): if '|' not in line: continue name, ts_str = line.split('|', 1) name = name.strip() try: ts = int(ts_str.strip()) except ValueError: continue display = get_author_display(name) # record the earliest (min) timestamp per display-name if display not in first_commit_ts or ts < first_commit_ts[display]: first_commit_ts[display] = ts # sort by that timestamp ordered = sorted(first_commit_ts.items(), key=lambda kv: kv[1]) return [get_author_display(author) for author, _ in ordered] def process_file(file_path, pattern): """ Reads `file_path`, replaces any `/// @author xxx` line with all unique committers, and writes back if changed. """ with open(file_path, 'r', encoding='utf-8') as f: lines = f.readlines() updated = False new_lines = [] for line in lines: m = pattern.match(line) if m: authors = get_git_authors(file_path) if authors: author_list = ', '.join(authors) new_line = f'/// @author {author_list}\n' if new_line != line: line = new_line updated = True new_lines.append(line) if updated: with open(file_path, 'w', encoding='utf-8') as f: f.writelines(new_lines) print(f'Updated authors in: {file_path}') def main(root_dir): # Regex to match lines like: /// @author xxx author_pattern = re.compile(r'^\s*/// @author xxx$') for dirpath, dirnames, filenames in os.walk(root_dir): # skip .git folder if '.git' in dirnames: dirnames.remove('.git') for fname in filenames: full_path = os.path.join(dirpath, fname) # Only process text/code files; you can adjust the extensions if you like if full_path.lower().endswith(('.sol')): # Quick check to see if file contains the tag at all with open(full_path, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() if '/// @author' in content: process_file(full_path, author_pattern) if __name__ == '__main__': root = sys.argv[1] if len(sys.argv) > 1 else '.' main(root)