|
1 | 1 | import os |
| 2 | +import re |
| 3 | +import subprocess |
| 4 | +from datetime import datetime |
2 | 5 |
|
3 | | -# Define the copyright notice to be added |
4 | | -COPYRIGHT_NOTICE = """/* |
5 | | - * Copyright 2022-2025 Noah Ross |
| 6 | + |
| 7 | +NOTICE_TEMPLATE = """/* |
| 8 | + * Copyright {years} Noah Ross |
6 | 9 | * |
7 | 10 | * This file is part of PerPlayerKit. |
8 | 11 | * |
|
20 | 23 | * along with PerPlayerKit. If not, see <https://www.gnu.org/licenses/>. |
21 | 24 | */""" |
22 | 25 |
|
23 | | -def add_copyright_to_file(file_path): |
| 26 | +COPYRIGHT_LINE_RE = re.compile( |
| 27 | + r"^ \* Copyright (?P<years>\d{4}(?:-\d{4})?) Noah Ross$", |
| 28 | + re.MULTILINE, |
| 29 | +) |
| 30 | + |
| 31 | + |
| 32 | +def get_repo_root(start_path): |
| 33 | + try: |
| 34 | + result = subprocess.run( |
| 35 | + ["git", "rev-parse", "--show-toplevel"], |
| 36 | + cwd=start_path, |
| 37 | + capture_output=True, |
| 38 | + text=True, |
| 39 | + check=True, |
| 40 | + ) |
| 41 | + except (FileNotFoundError, subprocess.CalledProcessError): |
| 42 | + return None |
| 43 | + |
| 44 | + return result.stdout.strip() |
| 45 | + |
| 46 | + |
| 47 | +def get_copyright_years(file_path, repo_root): |
| 48 | + if repo_root is None: |
| 49 | + return str(datetime.now().year) |
| 50 | + |
| 51 | + relative_path = os.path.relpath(file_path, repo_root) |
| 52 | + |
| 53 | + try: |
| 54 | + result = subprocess.run( |
| 55 | + [ |
| 56 | + "git", |
| 57 | + "-C", |
| 58 | + repo_root, |
| 59 | + "log", |
| 60 | + "--follow", |
| 61 | + "--format=%ad", |
| 62 | + "--date=format:%Y", |
| 63 | + "--", |
| 64 | + relative_path, |
| 65 | + ], |
| 66 | + capture_output=True, |
| 67 | + text=True, |
| 68 | + check=True, |
| 69 | + ) |
| 70 | + except (FileNotFoundError, subprocess.CalledProcessError, ValueError): |
| 71 | + return str(datetime.now().year) |
| 72 | + |
| 73 | + years = [line.strip() for line in result.stdout.splitlines() if line.strip()] |
| 74 | + if not years: |
| 75 | + return str(datetime.now().year) |
| 76 | + |
| 77 | + newest_year = years[0] |
| 78 | + oldest_year = years[-1] |
| 79 | + if newest_year == oldest_year: |
| 80 | + return newest_year |
| 81 | + |
| 82 | + return f"{oldest_year}-{newest_year}" |
| 83 | + |
| 84 | + |
| 85 | +def write_updated_content(file_path, content): |
| 86 | + with open(file_path, "w", encoding="utf-8") as file: |
| 87 | + file.write(content) |
| 88 | + |
| 89 | + |
| 90 | +def add_copyright_to_file(file_path, repo_root): |
24 | 91 | """ |
25 | | - Add the copyright notice to a Java file if it doesn't already exist. |
| 92 | + Add or update the copyright notice on a Java file. |
26 | 93 | """ |
27 | | - with open(file_path, 'r+') as file: |
| 94 | + with open(file_path, "r", encoding="utf-8") as file: |
28 | 95 | content = file.read() |
29 | | - # Check if the copyright notice is already present |
30 | | - if COPYRIGHT_NOTICE in content: |
31 | | - print(f"Copyright notice already exists in: {file_path}") |
| 96 | + |
| 97 | + years = get_copyright_years(file_path, repo_root) |
| 98 | + notice = NOTICE_TEMPLATE.format(years=years) |
| 99 | + |
| 100 | + match = COPYRIGHT_LINE_RE.search(content) |
| 101 | + if match: |
| 102 | + if match.group("years") == years: |
| 103 | + print(f"Copyright notice already up to date in: {file_path}") |
32 | 104 | return |
33 | | - # Prepend the copyright notice |
34 | | - file.seek(0) |
35 | | - file.write(COPYRIGHT_NOTICE + "\n" + content) |
36 | | - print(f"Added copyright notice to: {file_path}") |
37 | 105 |
|
38 | | -def process_java_files(directory): |
| 106 | + updated_content = COPYRIGHT_LINE_RE.sub( |
| 107 | + f" * Copyright {years} Noah Ross", |
| 108 | + content, |
| 109 | + count=1, |
| 110 | + ) |
| 111 | + write_updated_content(file_path, updated_content) |
| 112 | + print(f"Updated copyright notice in: {file_path}") |
| 113 | + return |
| 114 | + |
| 115 | + write_updated_content(file_path, notice + "\n" + content) |
| 116 | + print(f"Added copyright notice to: {file_path}") |
| 117 | + |
| 118 | + |
| 119 | +def process_java_files(directory, repo_root): |
39 | 120 | """ |
40 | 121 | Recursively process all Java files in the given directory. |
41 | 122 | """ |
42 | 123 | for root, _, files in os.walk(directory): |
43 | 124 | for file in files: |
44 | | - if file.endswith('.java'): |
| 125 | + if file.endswith(".java"): |
45 | 126 | file_path = os.path.join(root, file) |
46 | | - add_copyright_to_file(file_path) |
| 127 | + add_copyright_to_file(file_path, repo_root) |
47 | 128 |
|
48 | | -if __name__ == "__main__": |
49 | | - # Replace this with the path to your project directory |
50 | | - project_directory = "./" |
51 | | - process_java_files(project_directory) |
52 | 129 |
|
| 130 | +if __name__ == "__main__": |
| 131 | + project_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 132 | + repo_root = get_repo_root(project_directory) |
| 133 | + process_java_files(project_directory, repo_root) |
0 commit comments