Coverage for smith / infrastructure / metadata.py: 100%
0 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-01 18:48 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-01 18:48 +0000
1"""Metadata adapter — persist and load template source info in .gitignore."""
3from pathlib import Path
5from smith.domain.value_objects import TemplateSource
6from smith.infrastructure.gitignore import START_MARKER, GitignoreManager
9class SectionMetadata:
10 """Store and retrieve template source metadata inside the gitignore section."""
12 def __init__(self, project_dir: Path) -> None:
13 """Initialise with the project root directory."""
14 self._gitignore = GitignoreManager(project_dir)
16 def save_source(self, source: TemplateSource) -> None:
17 """Write the source identifier into the smith-managed section header."""
18 lines = self._gitignore._read_lines()
19 bounds = self._gitignore._find_section_bounds(lines)
20 if bounds is None:
21 return
22 start = bounds[0]
23 header = f"{START_MARKER} source:{source.kind}:{source.location}\n"
24 lines[start] = header
25 self._gitignore._write_lines(lines)
27 def load_source(self) -> TemplateSource | None:
28 """Read the source identifier from the smith-managed section header."""
29 lines = self._gitignore._read_lines()
30 bounds = self._gitignore._find_section_bounds(lines)
31 if bounds is None:
32 return None
33 header = lines[bounds[0]].strip()
34 for part in header.split():
35 if part.startswith("source:"):
36 value = part[len("source:") :]
37 if ":" in value:
38 kind, location = value.split(":", 1)
39 return TemplateSource(kind=kind, location=location) # type: ignore[arg-type]
40 return None