Create isolated per-run workspace and copy needed code/assets into it.
(logs)
| 216 | pass |
| 217 | |
| 218 | def _prepare_workspace(logs): |
| 219 | """Create isolated per-run workspace and copy needed code/assets into it.""" |
| 220 | run_id = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + "-" + uuid.uuid4().hex[:8] |
| 221 | work_dir = RUNS_DIR / run_id |
| 222 | work_dir.mkdir(parents=True, exist_ok=True) |
| 223 | |
| 224 | # Per-run log & zip path |
| 225 | log_path = work_dir / "run.log" |
| 226 | zip_path = work_dir / "output.zip" |
| 227 | |
| 228 | logs.append(f"🧩 New workspace: {work_dir.relative_to(ROOT)} (run_id={run_id})") |
| 229 | |
| 230 | # Copy code/assets that do file IO so they are run-local (avoid shared writes) |
| 231 | # Keep copies as cheap as possible (symlinks=True when supported) |
| 232 | needed_dirs = ["posterbuilder", "Paper2Poster"] |
| 233 | for d in needed_dirs: |
| 234 | src = ROOT / d |
| 235 | if src.exists(): |
| 236 | _copytree(src, work_dir / d, symlinks=True) |
| 237 | logs.append(f" ↪ copied {d}/ → runs/{run_id}/{d}/ (symlink where possible)") |
| 238 | |
| 239 | # template/ optional |
| 240 | tmpl = ROOT / "template" |
| 241 | if tmpl.exists(): |
| 242 | _copytree(tmpl, work_dir / "template", symlinks=True) |
| 243 | logs.append(" ↪ copied template/") |
| 244 | |
| 245 | # pipeline.py must live inside workspace so that ROOT_DIR=work_dir |
| 246 | _safe_copy(ROOT / "pipeline.py", work_dir / "pipeline.py") |
| 247 | |
| 248 | # Create standard IO dirs in workspace |
| 249 | (work_dir / "input" / "pdf").mkdir(parents=True, exist_ok=True) |
| 250 | (work_dir / "input" / "logo").mkdir(parents=True, exist_ok=True) |
| 251 | (work_dir / "posterbuilder" / "latex_proj").mkdir(parents=True, exist_ok=True) |
| 252 | |
| 253 | return run_id, work_dir, log_path, zip_path |
| 254 | |
| 255 | # --------------------- |
| 256 | # Helpers for new features (post-processing) |
no test coverage detected