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

1"""Metadata adapter — persist and load template source info in .gitignore.""" 

2 

3from pathlib import Path 

4 

5from smith.domain.value_objects import TemplateSource 

6from smith.infrastructure.gitignore import START_MARKER, GitignoreManager 

7 

8 

9class SectionMetadata: 

10 """Store and retrieve template source metadata inside the gitignore section.""" 

11 

12 def __init__(self, project_dir: Path) -> None: 

13 """Initialise with the project root directory.""" 

14 self._gitignore = GitignoreManager(project_dir) 

15 

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) 

26 

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