Files

81 lines
2.6 KiB
Python
Raw Permalink Normal View History

#!/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<opts>(?:-o\s+\S+\s+)*)update\s*$"
)
INSTALL_RE = re.compile(r"^RUN\s+(?P<rest>apt-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))