#!/usr/bin/env python3 """Apply HEADER.txt blocks to all project sources.""" from __future__ import annotations import argparse import sys from pathlib import Path from header_lib import ( REPO_ROOT, apply_header_to_content, has_valid_header, header_needs_identity_refresh, is_excluded_path, iter_source_files, ) def main() -> int: parser = argparse.ArgumentParser(description="Apply project headers to source files") parser.add_argument("--check", action="store_true", help="Only report files missing headers") parser.add_argument( "--fix-identity", action="store_true", help="Re-apply headers where contributors lack email but git has one", ) parser.add_argument("--path", type=str, default="", help="Limit to one file or directory") args = parser.parse_args() root = REPO_ROOT targets = list(iter_source_files(root)) if args.path: p = Path(args.path) if not p.is_absolute(): p = REPO_ROOT / p if p.is_file(): targets = [p] else: targets = [f for f in iter_source_files(root) if str(f).startswith(str(p))] missing = [] identity_fix = [] changed = 0 skipped_vendor = 0 for path in sorted(targets): if is_excluded_path(path): skipped_vendor += 1 continue text = path.read_text(encoding="utf-8", errors="replace") if args.check: if not has_valid_header(text): missing.append(path.relative_to(REPO_ROOT)) elif header_needs_identity_refresh(text, path): identity_fix.append(path.relative_to(REPO_ROOT)) continue if args.fix_identity: if not header_needs_identity_refresh(text, path) and has_valid_header(text): continue new_text = apply_header_to_content(path, text) if new_text != text: path.write_text(new_text, encoding="utf-8", newline="\n") changed += 1 if args.check: if missing: print("Missing headers:", len(missing)) for m in missing[:50]: print(" ", m) if len(missing) > 50: print(" ...") if identity_fix: print("Identity refresh suggested:", len(identity_fix)) for m in identity_fix[:30]: print(" ", m) if not missing and not identity_fix: print("All", len(targets) - skipped_vendor, "tracked files OK (third-party skipped).") return 0 return 1 if missing else 0 note = f" (skipped {skipped_vendor} under third-party/vendor paths)" if skipped_vendor else "" print(f"Updated {changed} / {len(targets) - skipped_vendor} source files{note}.") return 0 if __name__ == "__main__": sys.exit(main())