From 250077c592aacd016f7b586fa5dc530bec7a6cfd Mon Sep 17 00:00:00 2001 From: Marco D'Aleo Date: Sat, 13 Dec 2025 17:34:35 +0000 Subject: [PATCH] Add --inspect flag --- src/resrm/core.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/src/resrm/core.py b/src/resrm/core.py index d00c65f..e62a7e6 100644 --- a/src/resrm/core.py +++ b/src/resrm/core.py @@ -10,6 +10,7 @@ Basic usage: resrm --skip-trash file # permanent delete (bypass trash) resrm -l|--list # list trash entries (neat table) resrm --restore # restore by short-id (8 chars) or exact basename + resrm --inspect # output full detail list of trashed item resrm --empty # empty trash entries (permanent) """ @@ -374,6 +375,79 @@ def move_to_trash( print(f"Removed '{path}' -> trash id {short_id(uid)}") +def inspect_entry(identifier: str): + """Show full information about trash entries matching the identifier.""" + candidates = find_candidates(identifier) + + if not candidates: + print(f"No match found for '{identifier}'") + return + + for entry in candidates: + + # Validate entry structure + if not isinstance(entry, dict): + print(f"Invalid metadata entry (not a dict): {entry!r}") + print() + continue + + entry_id = entry.get("id") + orig_path = entry.get("orig_path", "?") + timestamp = entry.get("timestamp", "?") + + if not entry_id: + print(f"Invalid metadata entry (missing id): {entry}") + continue + + trash_path = TRASH_DIR / entry_id + + print(f"ID: {short_id(entry_id)}") + print(f"Original: {orig_path}") + print(f"Deleted at: {human_time(timestamp)}") + print(f"Stored at: {trash_path}") + + try: + st = trash_path.lstat() # preserves symlink info + import stat, pwd, grp + + # Type detection + if stat.S_ISDIR(st.st_mode): + ftype = "directory" + elif stat.S_ISLNK(st.st_mode): + try: + target = os.readlink(trash_path) + ftype = f"symlink → {target}" + except Exception: + ftype = "symlink" + else: + ftype = "file" + + # Permissions + perms = stat.filemode(st.st_mode) + + # Ownership + try: + user = pwd.getpwuid(st.st_uid).pw_name + except Exception: + user = st.st_uid + try: + group = grp.getgrgid(st.st_gid).gr_name + except Exception: + group = st.st_gid + owner = f"{user}:{group}" + + # Size (bytes for file, recursive for directories optional) + size = st.st_size + + print(f"Type: {ftype}") + print(f"Size: {size} bytes") + print(f"Permissions: {perms}") + print(f"Ownership: {owner}") + + except Exception as e: + print(f"Unknown stats for {e})") + + def main(argv: Optional[List[str]] = None): if argv is None: argv = sys.argv[1:] @@ -386,6 +460,15 @@ def main(argv: Optional[List[str]] = None): parser.add_argument( "--skip-trash", action="store_true", help="permanent delete" ) + + parser.add_argument( + "--inspect", + "-I", + nargs="+", + metavar="item", + help="show full metadata and original path for this trash entry", + ) + restore_arg = parser.add_argument( "--restore", nargs="+", @@ -424,7 +507,9 @@ def main(argv: Optional[List[str]] = None): print(__doc__) return - if not args.paths and not (args.list or args.empty or args.restore): + if not args.paths and not ( + args.list or args.empty or args.restore or args.inspect + ): print("resrm: missing operand") print("Try 'resrm --help' for more information.") return @@ -433,6 +518,11 @@ def main(argv: Optional[List[str]] = None): list_trash() return + if args.inspect: + for item in args.inspect: + inspect_entry(item) + return + if args.empty: empty_trash() return