#!/usr/bin/env python3 """ One-shot helper: add load_deployment_env to deployment/*.sh that still raw-source .env. Run from repo: python3 scripts/lib/deployment/patch-all-deployment-dotenv.py Idempotent: skips files that already call load_deployment_env. """ from __future__ import annotations import re from pathlib import Path ROOT = Path(__file__).resolve().parents[3] # smom-dbis-138 DEP = ROOT / "scripts" / "deployment" SNIPPET = """ # Load .env via dotenv (RPC CR/LF trim). Fallback: raw source. if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 source "$SCRIPT_DIR/../lib/deployment/dotenv.sh" load_deployment_env --repo-root "${PROJECT_ROOT:-$REPO_ROOT}" elif [[ -n "${PROJECT_ROOT:-}" && -f "$PROJECT_ROOT/.env" ]]; then set -a # shellcheck disable=SC1090 source "$PROJECT_ROOT/.env" set +a elif [[ -n "${REPO_ROOT:-}" && -f "$REPO_ROOT/.env" ]]; then set -a # shellcheck disable=SC1090 source "$REPO_ROOT/.env" set +a fi """.lstrip("\n") REMOVE_SUBSTRINGS = [ "\nsource .env 2>/dev/null || true\n", "\nsource .env 2>/dev/null || true", "\n[[ -f \"$PROJECT_ROOT/.env\" ]] && set -a && source \"$PROJECT_ROOT/.env\" && set +a\n", "\n[[ -f .env ]] && set -a && source .env && set +a\n", "\n[ -f .env ] && set -a && source .env && set +a\n", ] SET_U_BLOCK = re.compile( r"\nset \+u\n\[ -f \.env \] && source \.env\nset -u\n", re.MULTILINE ) DOTENV_IF = re.compile( r"\nif \[\[ -f \"\$DOTENV\" \]\]; then set -a; source \"\$DOTENV\"; set \+a; fi\n", re.MULTILINE, ) def find_insert_line(lines: list[str]) -> int | None: for i, line in enumerate(lines): s = line.strip() if re.match(r'^cd "\$(PROJECT_ROOT|REPO_ROOT)"\s*$', s): return i + 1 for i, line in enumerate(lines[:30]): if "PROJECT_ROOT=" in line and "$(cd" in line: return i + 1 if "REPO_ROOT=" in line and "$(cd" in line: return i + 1 return None def main() -> None: changed = 0 for path in sorted(DEP.glob("*.sh")): text = path.read_text(encoding="utf-8", errors="replace") if "load_deployment_env" in text: continue if "SCRIPT_DIR=" not in text or ( "PROJECT_ROOT=" not in text and "REPO_ROOT=" not in text ): continue lines = text.splitlines(keepends=True) ins = find_insert_line(lines) if ins is None: continue window = "".join(lines[max(0, ins - 2) : min(len(lines), ins + 8)]) if "load_deployment_env" in window: continue new_body = "".join(lines) new_body = SET_U_BLOCK.sub("\n", new_body) new_body = DOTENV_IF.sub("\n", new_body) for sub in REMOVE_SUBSTRINGS: new_body = new_body.replace(sub, "\n", 1) lines = new_body.splitlines(keepends=True) ins = find_insert_line(lines) if ins is None: continue lines.insert(ins, SNIPPET + ("\n" if not SNIPPET.endswith("\n") else "")) out = "".join(lines) if out != text: path.write_text(out, encoding="utf-8") changed += 1 print("patched", path.relative_to(ROOT)) print("done, changed", changed, "files") if __name__ == "__main__": main()