#!/usr/bin/env python3 """Merge a Dockerfile's split `apt-get update` + `apt-get install` into one RUN. Why: several imported challenge Dockerfiles run RUN apt-get -o Acquire::AllowInsecureRepositories=true update RUN apt-get -y --allow-unauthenticated install -y ... as two separate layers. The bundled apt-insecure.conf enables insecure/downgrade repositories, and a second apt invocation in a later layer re-resolves against whatever index the first one left behind — which on the EOL bullseye-security mirror returns 404 for every package: Err:1 http://deb.debian.org/debian-security bullseye-security/main amd64 libsystemd0 404 Not Found Merging them into a single `update && install` layer (the pattern the working gemastik18 challenges use) makes apt resolve once, from a fresh index. Idempotent: a Dockerfile that already has the combined form is left untouched. """ import re import sys from pathlib import Path SERVICES = Path("/opt/gemastik18-final/services") UPDATE_RE = re.compile( r"^RUN\s+apt-get\s+(?P(?:-o\s+\S+\s+)*)update\s*$" ) INSTALL_RE = re.compile(r"^RUN\s+(?Papt-get\s+.*\binstall\b.*)$") def fix(text: str) -> tuple[str, bool]: lines = text.splitlines() out: list[str] = [] i = 0 changed = False while i < len(lines): m = UPDATE_RE.match(lines[i]) if not m: out.append(lines[i]) i += 1 continue # look ahead: is the very next non-empty line an install? j = i + 1 while j < len(lines) and not lines[j].strip(): j += 1 if j < len(lines): mi = INSTALL_RE.match(lines[j]) if mi: out.append(f"RUN apt-get {m.group('opts')}update && \\") out.append(f" {mi.group('rest')}") changed = True i = j + 1 continue out.append(lines[i]) i += 1 return "\n".join(out) + ("\n" if text.endswith("\n") else ""), changed def main(argv): names = argv[1:] or [p.name for p in sorted(SERVICES.iterdir()) if p.is_dir() and (p / "Dockerfile").exists()] changed = [] for name in names: p = SERVICES / name / "Dockerfile" if not p.exists(): continue text = p.read_text() new, did = fix(text) if did: p.write_text(new) changed.append(name) print(f"{name}: merged apt update+install into one RUN") print("rewritten:", ", ".join(changed) if changed else "(none)") return 0 if __name__ == "__main__": raise SystemExit(main(sys.argv))