Init
This commit is contained in:
71
ptdiag/result.py
Normal file
71
ptdiag/result.py
Normal file
@@ -0,0 +1,71 @@
|
||||
"""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}")
|
||||
|
||||
Reference in New Issue
Block a user