"""Works out what SaraSortd made on its own while running, by reading GlobalConf.toml the same way SaraSortd.py does (see its Parse/GetConf/Init). It never removes the user's files: the input/output/failed folders are only removed if they're empty once SaraSortd's own files are gone. """ import re from pathlib import Path import tomlkit from Manifests import Leftover def _Find(Conf: dict, Key: str): """SaraSortd's GetConf: a top-level key, or one inside a table/array of tables.""" if Key in Conf: return Conf[Key] for Value in Conf.values(): if isinstance(Value, dict) and Key in Value: return Value[Key] if isinstance(Value, list): for Item in Value: if isinstance(Item, dict) and Key in Item: return Item[Key] return None def _Resolve(Text: str, Conf: dict) -> str: """SaraSortd's %Var% substitution (single pass, like its Parse).""" VarCall = Conf.get("Variables", {}).get("VarCall", "%%") Pattern = f"{re.escape(VarCall[0])}(.*?){re.escape(VarCall[1])}" def Replace(Match: re.Match) -> str: Value = _Find(Conf, Match[1]) if Match[1] else None return str(Value) if Value is not None else Match[0] return re.sub(Pattern, Replace, Text) def _DirFileName(Conf: dict, NameKey: str, DirPath: Path) -> str: """e.g. ".@Config" for a folder named Input -> ".InputConfig.toml".""" Parent = Conf.get("Variables", {}).get("Parent", "@") Name = Conf.get("Names", {}).get(NameKey, "") return f"{Name.replace(Parent, DirPath.name)}.toml" if Name else "" def Leftovers(Context: dict) -> list[Leftover]: ConfPath = Path(Context["ConfigDir"]) / "GlobalConf.toml" if not ConfPath.exists(): return [] try: Conf = tomlkit.parse(ConfPath.read_text()).unwrap() except tomlkit.exceptions.TOMLKitError: return [] Paths = Conf.get("DirectoryPaths", {}) Found: list[Leftover] = [] Folders = [] for Key in ("InputDir", "OutputDir"): Entries = Paths.get(Key, []) for Entry in Entries if isinstance(Entries, list) else [Entries]: Folders.append(Path(_Resolve(str(Entry), Conf))) for Folder in Folders: for NameKey in ("InDirConfName", "OutDirConfName", "DirConfName"): FileName = _DirFileName(Conf, NameKey, Folder) if FileName: Found.append(Leftover(str(Folder / FileName), "Config", Note="this folder's SaraSortd rules")) HistoryName = _DirFileName(Conf, "FileHistoryName", Folder) if HistoryName: Found.append(Leftover(str(Folder / HistoryName), "Runtime", Note="sorting history")) Found.append(Leftover(str(Folder), "Runtime", "IfEmpty", "only if empty")) LogDir = Paths.get("LogDir") if LogDir: LogDir = _Resolve(str(LogDir), Conf) Found.append(Leftover(f"{LogDir}/*.log", "Runtime", Note="log")) Found.append(Leftover(LogDir, "Runtime", "IfEmpty", "only if empty")) FailedDir = Paths.get("FailedDir") if FailedDir: Found.append(Leftover(_Resolve(str(FailedDir), Conf), "Runtime", "IfEmpty", "only if empty, it holds files that failed to sort")) RootDir = Paths.get("RootDir") if RootDir and RootDir != "Unset": Found.append(Leftover(_Resolve(str(RootDir), Conf), "Runtime", "IfEmpty", "only if empty")) return Found