"""Unique result-directory creation and JSON output.""" from __future__ import annotations from dataclasses import dataclass from datetime import datetime import json import os from pathlib import Path import re from typing import Any, Mapping @dataclass(frozen=True) class ResultDirectory: path: Path metadata_path: Path commands_path: Path def create_result_directory( root: Path, test_name: str, started_at: datetime | None = None, ) -> ResultDirectory: name = _slug(test_name) started = started_at or datetime.now().astimezone() base_name = f"{started:%Y%m%d-%H%M%S}-{name}" root.mkdir(parents=True, exist_ok=True) path = _mkdir_unique(root, base_name) metadata_path = path / "metadata.json" commands_path = path / "commands.log" commands_path.touch(exist_ok=False) write_json( metadata_path, { "test": name, "started_at": started.isoformat(), "result_directory": str(path), }, ) return ResultDirectory(path, metadata_path, commands_path) def write_json(path: Path, value: Mapping[str, Any]) -> None: path.parent.mkdir(parents=True, exist_ok=True) temporary = path.with_name(f".{path.name}.{os.getpid()}.tmp") with temporary.open("w", encoding="utf-8") as handle: json.dump(value, handle, indent=2, sort_keys=True) handle.write("\n") temporary.replace(path) def _slug(value: str) -> str: result = re.sub(r"[^a-z0-9]+", "-", value.casefold()).strip("-") if not result: raise ValueError("test_name must contain a letter or digit") return result def _mkdir_unique(root: Path, base_name: str) -> Path: for index in range(1000): suffix = "" if index == 0 else f"-{index:02d}" candidate = root / f"{base_name}{suffix}" try: candidate.mkdir() except FileExistsError: continue return candidate raise FileExistsError(f"Could not allocate a unique result directory for {base_name}")