Supporta utente target per percorsi watchdog
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -5,6 +5,7 @@ autostart = true
|
||||
autostart = true
|
||||
|
||||
[watch]
|
||||
target_user = ""
|
||||
include_dirs = [
|
||||
"%USERPROFILE%\\\\Desktop",
|
||||
"%USERPROFILE%\\\\Documents",
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user