import shelve from os import access, X_OK from pathlib import Path from collections import UserDict from functools import reduce from operator import or_ class DictSetMerge(UserDict): def __or__(self, other): results = self.copy() for key, paths in other.items(): if key in results: results[key] |= paths else: results[key] = paths return results def __getitem__(self, key): if key not in self: paths = set() self[key] = paths return paths else: return super().__getitem__(key) def add(self, key: str | Path, paths: set[Path] | None = None): """ Add a single Path if key is a Path object. Otherwise add values to the set. """ if not isinstance(key, Path) and paths is None: raise ValueError("Values allowed only to be None, if key is a Path") if not paths: paths = [key] key = key.name if key in self: self[key] |= set(paths) else: self[key] = set(paths) def make_db(root) -> DictListMerge: results = DictSetMerge() for file in Path(root).rglob("*"): if file.is_file() and access(file, X_OK): results.add(file) return results db_file = Path("db.shelve") if db_file.exists(): with shelve.open(db_file) as sh: db = DictListMerge(sh) else: paths = ["/bin","/sbin","/usr/sbin","/usr/lib","/home/deadeye/.local/"] db = reduce(or_, map(make_db, paths)) with shelve.open(db_file) as sh: sh.update(db)