60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
|
|
"""Per-project state for os-status (deep module).
|
||
|
|
|
||
|
|
Owns the gitignored .cc-os/ directory contract: key=value config, per-check
|
||
|
|
once-per-day snooze stamps (snooze-<check>), and permanent suppress markers
|
||
|
|
(suppress-<check>). State only, never code; nothing here writes outside
|
||
|
|
.cc-os/. Fail-open throughout: unreadable state reads as unset.
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from datetime import date
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Optional
|
||
|
|
|
||
|
|
|
||
|
|
def find_project_root(cwd: Path) -> Optional[Path]:
|
||
|
|
"""Nearest ancestor (including cwd) containing .git, else None."""
|
||
|
|
for candidate in [cwd, *cwd.parents]:
|
||
|
|
if (candidate / ".git").exists():
|
||
|
|
return candidate
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def read_config(root: Path) -> dict:
|
||
|
|
"""Parse .cc-os/config as '#'-commented key = value lines."""
|
||
|
|
config = {}
|
||
|
|
try:
|
||
|
|
text = (root / ".cc-os" / "config").read_text()
|
||
|
|
except Exception:
|
||
|
|
return config
|
||
|
|
for line in text.splitlines():
|
||
|
|
line = line.strip()
|
||
|
|
if not line or line.startswith("#") or "=" not in line:
|
||
|
|
continue
|
||
|
|
key, value = line.split("=", 1)
|
||
|
|
config[key.strip()] = value.strip()
|
||
|
|
return config
|
||
|
|
|
||
|
|
|
||
|
|
class StateDir:
|
||
|
|
"""The gitignored per-project .cc-os/ state directory."""
|
||
|
|
|
||
|
|
def __init__(self, root: Path) -> None:
|
||
|
|
self._dir = root / ".cc-os"
|
||
|
|
|
||
|
|
def suppressed(self, check: str) -> bool:
|
||
|
|
return (self._dir / f"suppress-{check}").exists()
|
||
|
|
|
||
|
|
def snoozed(self, check: str, today: date) -> bool:
|
||
|
|
try:
|
||
|
|
stamped = date.fromisoformat(
|
||
|
|
(self._dir / f"snooze-{check}").read_text().strip()
|
||
|
|
)
|
||
|
|
except Exception:
|
||
|
|
return False
|
||
|
|
return stamped == today
|
||
|
|
|
||
|
|
def stamp(self, check: str, today: date) -> None:
|
||
|
|
self._dir.mkdir(exist_ok=True)
|
||
|
|
(self._dir / f"snooze-{check}").write_text(today.isoformat())
|