fix: config save broken (relative_to→relpath), startup validation, auto-create, untrack config.yaml
- _relative_path(): replace Path.relative_to() with os.path.relpath() (ValueError crossing filesystems silently returned absolute paths) - _sync_config_from_ui(): always derive relative from get_path() absolute, never trust stale FileSelector._relative_path after Browse - validate_paths(): check all file paths exist on startup, clear missing - Clear UI selectors after validation to prevent re-save of stale paths - _load_config(): auto-create blank config.yaml when missing on disk - .gitignore: add config.yaml (user-specific, must not be tracked)
This commit is contained in:
+34
-2
@@ -190,8 +190,11 @@ class Config:
|
||||
def _relative_path(self, path: str) -> str:
|
||||
"""Convert an absolute path to a relative path from the config file.
|
||||
|
||||
Uses :func:`os.path.relpath` which works across filesystem
|
||||
boundaries (unlike :meth:`Path.relative_to`).
|
||||
|
||||
Args:
|
||||
path: Absolute path string.
|
||||
path: Absolute or relative path string.
|
||||
|
||||
Returns:
|
||||
Relative path string, or the original if conversion fails.
|
||||
@@ -201,7 +204,8 @@ class Config:
|
||||
try:
|
||||
target = Path(path)
|
||||
if target.is_absolute():
|
||||
return str(target.relative_to(self._config_path.parent))
|
||||
base = str(self._config_path.parent)
|
||||
return os.path.relpath(str(target), base)
|
||||
except (ValueError, OSError):
|
||||
pass
|
||||
return path
|
||||
@@ -219,6 +223,34 @@ class Config:
|
||||
return Path()
|
||||
return (self._config_path.parent / relative_path).resolve()
|
||||
|
||||
def validate_paths(self) -> list[str]:
|
||||
"""Validate file paths in config and clear those that don't exist.
|
||||
|
||||
Checks each file path field, resolves it against the config
|
||||
directory, and clears it if the target file does not exist
|
||||
on the current filesystem.
|
||||
|
||||
Returns:
|
||||
List of field names that were cleared.
|
||||
"""
|
||||
cleared: list[str] = []
|
||||
path_fields = [
|
||||
"bootloader_bit_path",
|
||||
"bootloader_elf_path",
|
||||
"bootloader_bin_path",
|
||||
"fsbl_elf_path",
|
||||
"firmware_bin_path",
|
||||
]
|
||||
for attr in path_fields:
|
||||
val = getattr(self, attr, "")
|
||||
if not val:
|
||||
continue
|
||||
resolved = self.resolve_path(val)
|
||||
if not resolved.is_file():
|
||||
setattr(self, attr, "")
|
||||
cleared.append(attr)
|
||||
return cleared
|
||||
|
||||
@property
|
||||
def config_path(self) -> Path | None:
|
||||
"""Return the path to the config file on disk."""
|
||||
|
||||
Reference in New Issue
Block a user