#!/usr/bin/env python3 # MobileGL - scripts/update-source-file-header.py # Copyright (c) 2025-2026 MobileGL-Dev # Licensed under the GNU Lesser General Public License v3.0: # https://www.gnu.org/licenses/gpl-3.0.txt # https://www.gnu.org/licenses/lgpl-3.0.txt # SPDX-License-Identifier: LGPL-3.0-only # End of Source File Header """Add the license header to source files that lack it. python3 scripts/update-source-file-header.py # every tracked source file it covers python3 scripts/update-source-file-header.py FILE ... # only these files python3 scripts/update-source-file-header.py --check # list what needs attention, exit 1 if anything does Covered under MobileGL/, scripts/ and tools/: C, C++ and .inc files with // comments and Python scripts with # comments. An existing header is kept as written, since its copyright years belong to the file; only a first line that names a different path is corrected. Generated files and files under another license are left alone. Files with mixed line endings are reported, never rewritten. """ import os import re import subprocess import sys ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) MARKER = "End of Source File Header" HEADER = """{c} MobileGL - {path} {c} Copyright (c) 2025-2026 MobileGL-Dev {c} Licensed under the GNU Lesser General Public License v3.0: {c} https://www.gnu.org/licenses/gpl-3.0.txt {c} https://www.gnu.org/licenses/lgpl-3.0.txt {c} SPDX-License-Identifier: LGPL-3.0-only {c} End of Source File Header """ OWN_SPDX = "SPDX-License-Identifier: LGPL-3.0-only" DIRS = ("MobileGL/", "scripts/", "tools/") SLASH_EXT = (".h", ".hpp", ".cpp", ".cc", ".c", ".inc") HASH_EXT = (".py",) FOREIGN_LICENSE = re.compile(r"Apache License|Permission is hereby granted|MIT License|BSD License|" r"Mozilla Public License|zlib License") SPDX_RE = re.compile(r"SPDX-License-Identifier:\s*(\S+)") COPYRIGHT_RE = re.compile(r"Copyright\b.*") # Built against apitrace's glws/glproc interfaces; whether they are adapted from apitrace's own # sources is not settled, so they carry no MobileGL header until it is. EXEMPT = ("tools/trace_replay/apitrace_",) # plan() statuses: the first three need no action, the last four do. QUIET = ("ok", "foreign", "empty") FIXABLE = ("add", "fix-path") MANUAL = ("mixed-eol", "bad-header") def is_generated(path): return "/generated/" in path or "/gen/" in path or os.path.basename(path).startswith("generated_") def comment_prefix(path): if path.endswith(HASH_EXT): return "#" if path.endswith(SLASH_EXT): return "//" return None def covered(path): return (path.startswith(DIRS) and comment_prefix(path) is not None and not is_generated(path) and not path.startswith(EXEMPT)) def plan(path, text): """Return (status, new_text). new_text is set only for the FIXABLE statuses.""" if not text.strip(): return "empty", None bom = "" if text.startswith("") else "" text = text[len(bom):] if "\r\n" in text and re.search(r"(?