fix(extension): 自动镜像生成两缺陷——Dockerfile FROM 顺序+timeout 参数名

真实 docker build 冒烟暴露:
- render_dockerfile 把 LABEL 放在 FROM 之前,buildkit 报 no build stage
- _inspect_image/_cleanup_failed_build/collect_garbage 传 timeout=
  而 _run_docker 形参是 timeout_sec,调用即 TypeError

验证:175 真实 docker build 补装 pandas 3.0.5 成功、指纹去重
REUSE_OK、容器内 import 通过;全量 324/15/122/373 转绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 15:59:33 +08:00
co-authored by Claude Fable 5
parent 2a6315e615
commit bb560d7bea
@@ -139,8 +139,8 @@ def render_dockerfile(base_image: str, requirements: dict[str, Any],
pip, apt = _sorted_requirements(requirements)
fingerprint = image_fingerprint(base_image, requirements, tag_suffix)
lines = ["# auto-generated by extension_image (fingerprint=%s)" % fingerprint,
"LABEL plantai.ext.fingerprint=%s" % fingerprint,
f"FROM {base_image}:{tag_suffix}"]
f"FROM {base_image}:{tag_suffix}",
"LABEL plantai.ext.fingerprint=%s" % fingerprint]
if apt:
# 单依赖时尾反斜杠由 bash 忽略(命令结束符后接换行安全);多依赖续行
lines.append("RUN apt-get update && apt-get install -y --no-install-recommends " +
@@ -245,7 +245,7 @@ class ExtensionImageBuilder:
def _inspect_image(self, name: str) -> dict[str, Any]:
try:
result = self._run_docker(["docker", "inspect", name], timeout=60.0)
result = self._run_docker(["docker", "inspect", name], timeout_sec=60.0)
except FileNotFoundError:
return {"hit": False, "error": "docker 命令不可用"}
except subprocess.TimeoutExpired:
@@ -289,7 +289,7 @@ class ExtensionImageBuilder:
if listed.get("exit_code") == 0:
for line in str(listed.get("stdout") or "").splitlines():
if line.strip():
self._run_docker(["docker", "rmi", line.strip()], timeout=120.0)
self._run_docker(["docker", "rmi", line.strip()], timeout_sec=120.0)
except (FileNotFoundError, subprocess.TimeoutExpired):
pass
logger.info("extension image: 构建失败已清理 fingerprint=%s", fingerprint)
@@ -360,7 +360,7 @@ class ExtensionImageBuilder:
continue
removed = False
try:
result = self._run_docker(["docker", "rmi", name], timeout=300.0)
result = self._run_docker(["docker", "rmi", name], timeout_sec=300.0)
removed = result["exit_code"] == 0
if removed:
self.registry().drop(name)