|
#!/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) |