Fix directorysizes stuff

This commit is contained in:
2026-02-24 16:27:29 -08:00
parent 2af64d17be
commit 23839f980e
7 changed files with 234 additions and 136 deletions

View File

@ -5,7 +5,8 @@
(:import-from #:cl-xdg-trash/directorysizes
#:read-directorysizes-for-trash-directory
#:write-directorysizes-for-trash-directory
#:trashed-file-size)
#:trashed-file-size
#:prune-directorysizes)
(:import-from #:cl-xdg-trash/trashinfo
#:trashinfo-trash-directory
#:trashinfo-name
@ -14,7 +15,10 @@
#:trashinfo-info-file
#:trashinfo-trashed-file)
(:use #:cl)
(:export #:trashinfo-size
(:export #:*no-warnings*
#:*prune-directorysizes*
#:mark-directorysizes-dirty
#:trashinfo-size
#:flush-directorysizes-cache
#:format-size
#:parse-format-string
@ -31,33 +35,56 @@
(in-package :clash/format)
(defvar *no-warnings* nil
"If non-nil, don't print warning messages to *error-output*.")
(defvar *prune-directorysizes* nil
"If non-nil, prune the directorysizes cache when flushing it.")
(defvar *directorysizes-cache* (make-hash-table :test #'equal)
"Cache for directorysizes tables (trash-directory -> (need-flush . table)).")
(defun get-directorysizes-for-directory (directory)
"Return a directorysizes table for DIRECTORY. DIRECTORY should be a pathname
object."
(let ((cur-val (gethash directory *directorysizes-cache*)))
(or cur-val
(setf (gethash directory *directorysizes-cache*)
(cons nil (read-directorysizes-for-trash-directory directory))))))
(defun get-directorysizes-for-trashinfo (trashinfo)
"Return a directorysizes table for the trash-directory of TRASHINFO."
(let* ((trash-directory (trashinfo-trash-directory trashinfo))
(cur-val (gethash trash-directory *directorysizes-cache*)))
(if (hash-table-p cur-val)
cur-val
(setf (gethash trash-directory *directorysizes-cache*)
(cons nil
(read-directorysizes-for-trash-directory trash-directory))))))
(get-directorysizes-for-directory (trashinfo-trash-directory trashinfo)))
(defvar *trashinfo-size-cache* (make-hash-table :test #'eq)
"Cache for trashinfo sizes.")
(defun trashinfo-size (trashinfo)
"Return the size of TRASHINFO and cache it."
(defun mark-directorysizes-dirty (directory)
"Mark the trash directory DIRECTORY as needing to have its directorysizes
flushed."
(setf (car (get-directorysizes-for-directory directory)) t))
(defun trashinfo-size (trashinfo &optional no-warn)
"Return the size of TRASHINFO and cache it. If an error occurred while getting
the size, return nil. For a given trashinfo, the first time an error occurs,
print a warning to *ERROR-OUTPUT* unless NO-WARN is non-nil."
(let ((res (gethash trashinfo *trashinfo-size-cache* :none)))
(if (eq res :none)
(let ((directorysizes-pair (get-directorysizes-for-trashinfo trashinfo)))
(multiple-value-bind (size did-change)
(trashed-file-size
(trashinfo-trash-directory trashinfo)
(trashinfo-name trashinfo)
:directorysizes (cdr directorysizes-pair)
:no-write t)
(handler-case
(trashed-file-size
(trashinfo-trash-directory trashinfo)
(trashinfo-name trashinfo)
:directorysizes (cdr directorysizes-pair)
:no-write t)
(osicat-posix:posix-error (e)
(unless (or no-warn *no-warnings*)
(format
*error-output* "warning: failed to get size of ~S: ~A~%"
(uiop:native-namestring (trashinfo-trashed-file trashinfo))
(osicat-posix:strerror (osicat:system-error-code e))))
(values nil nil)))
(when did-change
(setf (car directorysizes-pair) t))
(setf (gethash trashinfo *trashinfo-size-cache*) size)))
@ -67,8 +94,12 @@
"Flush the cached directorysizes changes."
(maphash (lambda (trash-directory directorysizes-pair)
(when (car directorysizes-pair)
(write-directorysizes-for-trash-directory
trash-directory (cdr directorysizes-pair) t)))
(if *prune-directorysizes*
(prune-directorysizes
trash-directory :directorysizes (cdr directorysizes-pair)
:no-error t)
(write-directorysizes-for-trash-directory
trash-directory (cdr directorysizes-pair) t))))
*directorysizes-cache*))
(defun format-size (count &optional base-two (places 2))
@ -363,7 +394,8 @@ The recognized printf-style sequences for ~A are:
(make-format-code
:name #\s
:action (lambda (stream info)
(format stream "~A" (trashinfo-size info)))
(let ((size (trashinfo-size info)))
(format stream "~:[N/A~;~:*~A~]" size)))
:doc "the file's (s)size in bytes")
(make-format-code
:name #\h