Source code for pysnap.config.protosettings

"""Persistent storage for prototype clone settings."""

from __future__ import annotations

from pathlib import Path

from pysnap.errors import PySnapError


[docs] class ProtoSettingsStore: """Persist VM names that trigger extra clone settings.""" DEFAULT_FILENAME = ".ptotosettings" def __init__(self, path: Path | None = None) -> None: """Initialize the store. :param path: Optional file path override. """ self.path = path or (Path.home() / self.DEFAULT_FILENAME)
[docs] def list_vm_names(self) -> tuple[str, ...]: """Return configured VM names without duplicates. :returns: Configured VM names in file order. :raises PySnapError: If the file cannot be read. """ if not self.path.exists(): return () try: raw_lines = self.path.read_text(encoding="utf-8").splitlines() except OSError as error: raise PySnapError( f'Unable to read proto settings from "{self.path}": {error}' ) from error unique_names: list[str] = [] seen: set[str] = set() for line in raw_lines: vm_name = line.strip() if not vm_name or vm_name in seen: continue unique_names.append(vm_name) seen.add(vm_name) return tuple(unique_names)
[docs] def contains(self, vm_name: str) -> bool: """Return whether one VM name is configured. :param vm_name: VM name to check. :returns: ``True`` when the VM is configured. """ return vm_name in set(self.list_vm_names())
[docs] def add_vm_name(self, vm_name: str) -> tuple[str, ...]: """Add one VM name to the store. :param vm_name: VM name to persist. :returns: Updated VM names. :raises PySnapError: If the file cannot be written. """ vm_names = list(self.list_vm_names()) if vm_name not in vm_names: vm_names.append(vm_name) self._write_vm_names(vm_names) return tuple(vm_names)
[docs] def remove_vm_names(self, vm_names: list[str] | tuple[str, ...]) -> tuple[str, ...]: """Remove VM names from the store. :param vm_names: VM names to remove. :returns: Remaining VM names. :raises PySnapError: If the file cannot be written. """ current_names = list(self.list_vm_names()) if not current_names: return () remove_set = set(vm_names) remaining = [name for name in current_names if name not in remove_set] if remaining != current_names: self._write_vm_names(remaining) return tuple(remaining)
def _write_vm_names(self, vm_names: list[str]) -> None: """Write VM names to the store file. :param vm_names: VM names to write. :raises PySnapError: If the file cannot be written. """ try: self.path.parent.mkdir(parents=True, exist_ok=True) content = "\n".join(vm_names) if content: content = f"{content}\n" self.path.write_text(content, encoding="utf-8") except OSError as error: raise PySnapError( f'Unable to write proto settings to "{self.path}": {error}' ) from error