Adding autorender

This commit is contained in:
2026-07-30 20:42:25 +02:00
parent 9d29d2e2ed
commit 4470246ebb
2 changed files with 109 additions and 7 deletions
+10 -7
View File
@@ -65,10 +65,13 @@ fi
log "autorender start (HEAD $(git -C "$GNOMMO_DIR" rev-parse --short HEAD 2>/dev/null), user $(whoami))"
# ── Step 2: render loop — pending `gnommo auto` ────────────────────────────────
# When gnommo auto lands, replace the placeholder with:
# cd "$GNOMMO_DIR" && ./venv/bin/python -m gnommo auto 2>&1 | tee -a "$LOG" \
# || notify "autorender: gnommo auto reported failures"
log "render step not wired yet (gnommo auto pending) — code-deploy path is live"
log "autorender done"
# ── Step 2: render loop — per-project down → gated render → handoff ────────────
# `gnommo auto` scans video* under the cwd, so cd into the repo first. It returns
# non-zero if any project failed; we ping on that.
cd "$GNOMMO_DIR"
if ./venv/bin/python -m gnommo auto 2>&1 | tee -a "$LOG"; then
log "autorender done (all projects ok)"
else
log "autorender done WITH FAILURES (see log above)"
notify "autorender: one or more projects failed on the rig — check autorender.log"
fi
+99
View File
@@ -131,6 +131,7 @@ Examples:
"grade",
"all",
"align",
"auto",
"import",
"description",
"archive",
@@ -341,6 +342,8 @@ Examples:
if args.project is None:
if action == "pexels" and args.search:
project_path = Path.cwd() # placeholder; cmd_pexels won't use it in search mode
elif action == "auto":
project_path = Path.cwd() # auto scans this root for video* projects
else:
parser.error("argument -p/--project is required")
return 1
@@ -425,6 +428,8 @@ Examples:
return cmd_all(
project_path, args.verbose, args.dry_run, args.res, args.force
)
elif action == "auto":
return cmd_auto(project_path, args.verbose, args.dry_run, args.res)
elif action == "description":
return cmd_description(project_path, args.verbose)
elif action == "archive":
@@ -6171,6 +6176,100 @@ def cmd_all(
return cmd_up(project_path, verbose, dry_run)
# =============================================================================
# Auto Command — unattended render driver for the rig (called by autorender.sh)
# =============================================================================
def cmd_auto(
root: Path,
verbose: bool,
dry_run: bool,
res: str = "full",
prod: bool = True,
) -> int:
"""Unattended per-project driver: down → (commit-gated) render → handoff.
For every ``video*`` project under ``root`` (default: the current directory,
which autorender.sh cd's into), pull the latest tree from the relay, then —
only when the project's commits.log has an entry newer than the one this rig
last handled — run the gated pipeline (preprocess → trim → render, each of
which self-skips when its own inputs are unchanged) and hand the result off.
The commit timestamp is the explicit "this is ready" trigger, so incidental
file touches don't cause spurious re-renders or version bumps.
Returns non-zero if any project failed, so autorender.sh can ping on failure.
"""
from .transfer import cmd_down, _read_log_lines, _last_timestamp, _COMMITS_LOG
from .handoff import cmd_handoff
from . import state as _state
projects = sorted(
d for d in Path(root).glob("video*")
if d.is_dir() and (d / "project.json").exists()
)
if not projects:
print(f" No video* projects with project.json under {root}")
return 0
print(f"=== auto: {len(projects)} project(s) under {root} ===")
rendered: list[str] = []
skipped: list[str] = []
failed: list[tuple[str, str]] = []
for proj in projects:
name = proj.name
print(f"\n--- {name} ---")
# 1. Sync from the relay (brings the newest commits.log + inputs). Skipped
# in dry-run so it stays side-effect-free — we just report intent.
if not dry_run and cmd_down(proj, verbose, dry_run=False) != 0:
print(f" {name}: down failed")
failed.append((name, "down"))
continue
# 2. Commit trigger: is commits.log newer than what we last handled here?
latest = _last_timestamp(_read_log_lines(proj / _COMMITS_LOG))
handled = _state.get_items(proj, "auto").get("handled")
if latest is None:
print(f" {name}: no commits.log — skipping")
skipped.append(name)
continue
if latest == handled:
print(f" {name}: unchanged since {handled} — skipping")
skipped.append(name)
continue
print(f" {name}: new commit {latest} (last handled: {handled or 'never'})")
if dry_run:
print(" [dry-run] would preprocess → trim → render → handoff")
rendered.append(name)
continue
# 3. Gated pipeline — each stage self-skips when its inputs are unchanged;
# `or` short-circuits at the first non-zero (failing) stage.
rc = (
cmd_preprocess(proj, verbose, False, force=False, workers=1, res=res)
or cmd_trim(proj, verbose, force=False)
or cmd_render(proj, verbose, False, res=res, force=False)
or cmd_handoff(proj, verbose, None, prod, res)
)
if rc != 0:
print(f" {name}: pipeline failed (rc={rc})")
failed.append((name, f"rc={rc}"))
continue
# 4. Record this commit as handled so we don't re-render it next run.
_state.record_items(proj, "auto", {"handled": latest})
rendered.append(name)
print("\n=== auto summary ===")
print(f" rendered: {', '.join(rendered) or ''}")
print(f" skipped: {', '.join(skipped) or ''}")
print(f" failed: {', '.join(f'{n}({r})' for n, r in failed) or ''}")
return 1 if failed else 0
# =============================================================================
# Description Command
# =============================================================================