#!/usr/bin/env python3 """Detect uncommitted edits in upstream-owned source trees. Default mode (no flags): emit a human-readable report and exit 0. Strict mode (--strict, the default when REDBEAR_BUILD_PHASE is set): emit the same report and exit non-zero if any tree is dirty. This is how `build-redbear.sh` ensures that any edits to upstream-owned source trees under `recipes/core//source/` (which are symlinks into `local/sources//`) are detected and either committed or explicitly overridden via REDBEAR_ALLOW_DIRTY. The override is --no-strict, which forces exit 0 even when dirty. This matches the REDBEAR_ALLOW_DIRTY=1 escape hatch in build-redbear.sh. """ import argparse import os import subprocess import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] UPSTREAM_OWNED = { "kernel": PROJECT_ROOT / "recipes/core/kernel/source", "base": PROJECT_ROOT / "recipes/core/base/source", "relibc": PROJECT_ROOT / "recipes/core/relibc/source", "bootloader": PROJECT_ROOT / "recipes/core/bootloader/source", "installer": PROJECT_ROOT / "recipes/core/installer/source", "redoxfs": PROJECT_ROOT / "recipes/core/redoxfs/source", } def git_has_changes(repo: Path) -> tuple[bool, list[str]]: if not (repo / ".git").exists(): return False, [] proc = subprocess.run( ["git", "status", "--short"], cwd=repo, check=False, capture_output=True, text=True, ) lines = [line.rstrip() for line in proc.stdout.splitlines() if line.strip()] return bool(lines), lines def main() -> int: parser = argparse.ArgumentParser( description="Detect uncommitted edits in upstream-owned Red Bear OS source trees.", ) # Default to strict when invoked from a canonical build (REDBEAR_BUILD_PHASE # is set by build-redbear.sh). Default to non-strict for ad-hoc operator use. canonical = bool(os.environ.get("REDBEAR_BUILD_PHASE")) parser.add_argument( "--strict", action="store_true", default=canonical, help="Exit non-zero if any tree is dirty (default when REDBEAR_BUILD_PHASE is set)", ) parser.add_argument( "--no-strict", dest="strict", action="store_false", help="Always exit 0, even when dirty (override REDBEAR_BUILD_PHASE default)", ) args = parser.parse_args() dirty = False for label, repo in UPSTREAM_OWNED.items(): has_changes, lines = git_has_changes(repo) if not has_changes: continue dirty = True print(f"{label}\tDIRTY\t{repo.relative_to(PROJECT_ROOT)}") for line in lines[:20]: print(f" {line}") if len(lines) > 20: print(f" ... {len(lines) - 20} more") if args.strict and dirty: print("", file=sys.stderr) print("ERROR: uncommitted edits detected in upstream-owned source trees.", file=sys.stderr) print(" Use --no-strict to allow, or commit your changes.", file=sys.stderr) return 1 return 0 if __name__ == "__main__": sys.exit(main())