Supporta utente target per percorsi watchdog

This commit is contained in:
2026-07-02 09:22:12 +02:00
parent b0e29b4cc5
commit e5a76992d4
9 changed files with 130 additions and 11 deletions

View File

@@ -35,6 +35,7 @@ class BackupConfig:
@dataclass(frozen=True)
class WatchConfig:
target_user: str | None
include_dirs: tuple[Path, ...]
include_extensions: frozenset[str]
exclude_dirs: tuple[Path | str, ...]
@@ -158,11 +159,12 @@ def parse_config(data: dict[str, Any], path: Path) -> AppConfig:
storage = data.get("storage", {})
stability = data.get("stability", {})
include_dirs = tuple(expand_path(item) for item in watch.get("include_dirs", []))
target_user = _optional_string(watch.get("target_user"))
include_dirs = tuple(expand_path(item, target_user) for item in watch.get("include_dirs", []))
include_extensions = frozenset(
_normalize_extension(item) for item in watch.get("include_extensions", [])
)
exclude_dirs = tuple(_normalize_exclude_dir(item) for item in watch.get("exclude_dirs", []))
exclude_dirs = tuple(_normalize_exclude_dir(item, target_user) for item in watch.get("exclude_dirs", []))
storage_config = StorageConfig(
change_registry=expand_path(
@@ -180,6 +182,7 @@ def parse_config(data: dict[str, Any], path: Path) -> AppConfig:
service_autostart=bool(service.get("autostart", True)),
tray_autostart=bool(tray.get("autostart", True)),
watch=WatchConfig(
target_user=target_user,
include_dirs=include_dirs,
include_extensions=include_extensions,
exclude_dirs=exclude_dirs,
@@ -219,13 +222,20 @@ def _normalize_extension(value: str) -> str:
return value if value.startswith(".") else f".{value}"
def _normalize_exclude_dir(value: str) -> Path | str:
expanded = expand_path(value)
if "%" in value or not expanded.is_absolute():
def _normalize_exclude_dir(value: str, target_user: str | None = None) -> Path | str:
expanded = expand_path(value, target_user)
if "%" in str(expanded) or not expanded.is_absolute():
return value.lower()
return expanded
def _optional_string(value: object) -> str | None:
if value is None:
return None
text = str(value).strip()
return text or None
def _remote_destinations(backup: dict[str, Any]) -> tuple[str, ...]:
destinations = backup.get("remote_destinations")
if isinstance(destinations, list):

View File

@@ -56,16 +56,22 @@ class BakRestConfigApp(ctk.CTk):
def _build_monitor_tab(self) -> None:
self.monitor_tab.grid_columnconfigure(0, weight=1)
self.monitor_tab.grid_columnconfigure(1, weight=1)
self.monitor_tab.grid_rowconfigure(0, weight=1)
self.monitor_tab.grid_rowconfigure(1, weight=1)
target_frame = ctk.CTkFrame(self.monitor_tab)
target_frame.grid(row=0, column=0, columnspan=2, sticky="ew", padx=8, pady=(8, 0))
target_frame.grid_columnconfigure(1, weight=1)
self.target_user_var = tk.StringVar()
_label_entry(target_frame, "Utente percorsi", self.target_user_var, 0)
left = ctk.CTkFrame(self.monitor_tab)
left.grid(row=0, column=0, sticky="nsew", padx=(0, 8), pady=8)
left.grid(row=1, column=0, sticky="nsew", padx=(0, 8), pady=8)
left.grid_columnconfigure(0, weight=1)
left.grid_rowconfigure(1, weight=1)
left.grid_rowconfigure(3, weight=1)
right = ctk.CTkFrame(self.monitor_tab)
right.grid(row=0, column=1, sticky="nsew", padx=(8, 0), pady=8)
right.grid(row=1, column=1, sticky="nsew", padx=(8, 0), pady=8)
right.grid_columnconfigure(0, weight=1)
right.grid_rowconfigure(1, weight=1)
right.grid_rowconfigure(3, weight=1)
@@ -83,7 +89,7 @@ class BakRestConfigApp(ctk.CTk):
self.exclude_patterns.grid(row=2, column=0, rowspan=2, sticky="nsew", padx=12, pady=12)
actions = ctk.CTkFrame(self.monitor_tab, fg_color="transparent")
actions.grid(row=1, column=0, columnspan=2, sticky="ew", pady=(0, 8))
actions.grid(row=2, column=0, columnspan=2, sticky="ew", pady=(0, 8))
actions.grid_columnconfigure(0, weight=1)
save_button = ctk.CTkButton(actions, text="Salva configurazione", command=self._save_config)
@@ -169,6 +175,7 @@ class BakRestConfigApp(ctk.CTk):
backup = self.data.setdefault("backup", {})
server_check = backup.setdefault("server_check", {})
self.target_user_var.set(str(watch.get("target_user", "")))
self.include_dirs.set_items(watch.get("include_dirs", []))
self.extensions.set_items(watch.get("include_extensions", []))
self.exclude_dirs.set_items(watch.get("exclude_dirs", []))
@@ -187,6 +194,7 @@ class BakRestConfigApp(ctk.CTk):
server_check = backup.setdefault("server_check", {})
watch["include_dirs"] = self.include_dirs.items()
watch["target_user"] = self.target_user_var.get().strip()
watch["include_extensions"] = self.extensions.items()
watch["exclude_dirs"] = self.exclude_dirs.items()
watch["exclude_patterns"] = self.exclude_patterns.items()

View File

@@ -5,6 +5,7 @@ autostart = true
autostart = true
[watch]
target_user = ""
include_dirs = [
"%USERPROFILE%\\\\Desktop",
"%USERPROFILE%\\\\Documents",

View File

@@ -22,5 +22,45 @@ def default_config_path() -> Path:
return program_data_dir() / "config.toml"
def expand_path(value: str) -> Path:
return Path(os.path.expandvars(value)).expanduser()
def expand_path(value: str, target_user: str | None = None) -> Path:
expanded = expand_user_vars(value, target_user)
return Path(os.path.expandvars(expanded)).expanduser()
def expand_user_vars(value: str, target_user: str | None = None) -> str:
if not target_user:
return value
user = target_user.strip().lstrip(".\\")
if not user:
return value
profile = Path("C:/Users") / user
replacements = {
"%USERPROFILE%": str(profile),
"%APPDATA%": str(profile / "AppData" / "Roaming"),
"%LOCALAPPDATA%": str(profile / "AppData" / "Local"),
"%TEMP%": str(profile / "AppData" / "Local" / "Temp"),
"%TMP%": str(profile / "AppData" / "Local" / "Temp"),
}
expanded = value
for token, replacement in replacements.items():
expanded = _replace_case_insensitive(expanded, token, replacement)
return expanded
def _replace_case_insensitive(value: str, old: str, new: str) -> str:
lower_value = value.lower()
lower_old = old.lower()
start = 0
parts: list[str] = []
while True:
index = lower_value.find(lower_old, start)
if index == -1:
parts.append(value[start:])
break
parts.append(value[start:index])
parts.append(new)
start = index + len(old)
return "".join(parts)