fix(extension): 产物收割排除代码副本+删 work 目录——输出契约校验语义不变

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 11:59:42 +08:00
co-authored by Claude Fable 5
parent 3989dd3c3a
commit a008fbba2a
+29 -15
View File
@@ -266,27 +266,39 @@ def _find_code_dir(ext_dir: Path) -> Path | None:
return None
def _copy_code_tree(src: Path, dst: Path) -> None:
"""把代码树复制进可写目录(shutil.copytree,目标已存在)。"""
def _copy_code_tree(src: Path, dst: Path) -> set[str]:
"""把代码树复制进可写目录;返回原始代码相对路径集合(收割时排除)。"""
import shutil
rels: set[str] = set()
if not src.is_dir():
return
for item in src.iterdir():
dest = dst / item.name
return rels
for item in src.rglob("*"):
rel = item.relative_to(src).as_posix()
dest = dst / rel
if item.is_dir():
shutil.copytree(item, dest, dirs_exist_ok=True)
dest.mkdir(parents=True, exist_ok=True)
else:
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(item, dest)
rels.add(rel)
return rels
def _merge_tree(src: Path, dst: Path) -> None:
"""把 src 全部内容合并进 dst(含子目录;同名覆盖)。"""
def _harvest_outputs(src: Path, dst: Path, exclude: set[str]) -> None:
"""把 src 内产物(排除原始代码路径)合并进 dst,保留相对路径。"""
import shutil
for item in src.iterdir():
dest = dst / item.name
for item in src.rglob("*"):
rel = item.relative_to(src).as_posix()
if rel in exclude:
continue
# 排除路径是原始代码文件所在目录时也跳过其祖先目录本身
if any(rel == e or rel.startswith(e + "/") for e in exclude):
continue
dest = dst / rel
if item.is_dir():
shutil.copytree(item, dest, dirs_exist_ok=True)
dest.mkdir(parents=True, exist_ok=True)
else:
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(item, dest)
@@ -390,9 +402,9 @@ def main(argv: list[str] | None = None) -> int:
# 2026-09-15 修复:代码挂载只读,但 18 用例语义是「cd 代码目录后脚本写
# outputs/ 相对目录」。等价做法 = 把代码复制进可写 run_dir 执行,
# 结束后把 run_dir 产物收割进 output_dir。显式 --work-dir 可覆盖。
work_dir = Path(args.work_dir) if args.work_dir else (output_dir / "work")
work_dir = Path(args.work_dir) if args.work_dir else (output_dir / "_work")
work_dir.mkdir(parents=True, exist_ok=True)
_copy_code_tree(code_dir, work_dir)
code_rel_paths = _copy_code_tree(code_dir, work_dir)
# 模板中 {code_dir} 指向可写副本(而非只读挂载)
effective_code_dir = work_dir
@@ -439,9 +451,11 @@ def main(argv: list[str] | None = None) -> int:
if code != EXIT_OK:
print(f"[run_extension] command exited with code {code}", file=sys.stderr)
return code
# 收割:work_dir 内全部产物(含 outputs/ 子目录与中间文件)合并进 output_dir
# 收割:work_dir 产物(排除原始代码文件)合并进 output_dir,然后删除 work 目录
try:
_merge_tree(work_dir, output_dir)
_harvest_outputs(work_dir, output_dir, code_rel_paths)
import shutil
shutil.rmtree(work_dir, ignore_errors=True)
except OSError as exc:
print(f"[run_extension] 产物收割失败: {exc}", file=sys.stderr)
return EXIT_SETUP