| 270 | |
| 271 | @contextmanager |
| 272 | def file_lock(paths: Paths, name: str = "compile.lock", stale_after_seconds: int = DEFAULT_LOCK_STALE_SECONDS) -> Iterator[Path]: |
| 273 | ensure_runtime_dirs(paths) |
| 274 | lock_path = compiler_lock_path(paths, name=name) |
| 275 | status = lock_status(paths, stale_after_seconds=stale_after_seconds, name=name) |
| 276 | if status["locked"] and not status["stale"]: |
| 277 | raise CompileLockError(f"compile already locked: {lock_path}") |
| 278 | if status["locked"] and status["stale"] and lock_path.exists(): |
| 279 | lock_path.unlink() |
| 280 | payload = { |
| 281 | "created_at": utc_now().replace(microsecond=0).isoformat().replace("+00:00", "Z"), |
| 282 | "pid": os.getpid(), |
| 283 | } |
| 284 | atomic_write_json(lock_path, payload) |
| 285 | try: |
| 286 | yield lock_path |
| 287 | finally: |
| 288 | if lock_path.exists(): |
| 289 | lock_path.unlink() |