emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/dired-duplicates 5b2a23dd52 01/57: Check in first worki


From: ELPA Syncer
Subject: [elpa] externals/dired-duplicates 5b2a23dd52 01/57: Check in first working version
Date: Sat, 4 Nov 2023 06:58:25 -0400 (EDT)

branch: externals/dired-duplicates
commit 5b2a23dd52749c8c56815faa1e3455fae858aae0
Author: Harald Judt <h.judt@gmx.at>
Commit: Harald Judt <h.judt@gmx.at>

    Check in first working version
---
 find-dupes-dired.el | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

diff --git a/find-dupes-dired.el b/find-dupes-dired.el
new file mode 100644
index 0000000000..738bb1fb08
--- /dev/null
+++ b/find-dupes-dired.el
@@ -0,0 +1,96 @@
+(defcustom find-dupes-separator-file
+  (concat "/tmp/-" (make-string 40 ?-))
+  "Path and name of the separator file that will be created (and deleted) for 
making search results easier to discern."
+  :group 'find-dupes-dired
+  :tag "Dummy separator file. It will be created immediately before and 
deleted as soon as possible after the search operation finishes."
+  :type 'string)
+
+(defcustom find-dupes-checksum-exec
+  "sha256sum"
+  "Name of the executable used for creating file checksums for comparison."
+  :group 'find-dupes-dired
+  :tag "Checksum executable"
+  :type 'string)
+
+(defvar find-dupes-directories nil
+  "List of directories that will be searched for duplicate files.")
+
+(defun find-dupes-checksum-file (file)
+  "Create a checksum for `file', using executable defined by 
`find-dupes-checksum-exec'."
+  (let* ((default-directory (file-name-directory (expand-file-name file)))
+         (exec (executable-find find-dupes-checksum-exec t)))
+    (unless exec
+      (error "Checksum program %s not found in exec-path!" exec))
+    (first (split-string
+            (shell-command-to-string
+             (concat exec " \"" (expand-file-name (file-local-name file)) 
"\""))
+            nil
+            t))))
+
+(defun find-dupes--ensure-separator-file ()
+  "Ensure that the separator file specified by `find-dupes-separator-file' 
exists."
+    (unless (file-exists-p find-dupes-separator-file)
+      (make-empty-file find-dupes-separator-file)))
+
+(defun find-dupes--remove-separator-file ()
+  "Remove the separator file specified by `find-dupes-separator-file'."
+  (delete-file find-dupes-separator-file nil))
+
+(defun find-dupes--duplicate-files (directories)
+  "Given one or more root directories, search inside below the
+directories for duplicate files. Returns a hash-table with the
+generated checksums as keys and files as values."
+  (cl-loop with files = (mapcan #'(lambda (d) (directory-files-recursively d 
".*"))
+                                (ensure-list directories))
+           and same-size-table = (make-hash-table)
+           and checksum-table = (make-hash-table :test 'equal)
+           for f in files
+           for size = (file-attribute-size (file-attributes f))
+           do (setf (gethash size same-size-table)
+                    (append (gethash size same-size-table) (list f)))
+           finally
+           (cl-loop for size being the hash-key in same-size-table using 
(hash-value same-size-files)
+                    if (> (length same-size-files) 1) do
+                    (cl-loop for f in same-size-files
+                             for checksum = (find-dupes-checksum-file f)
+                             do (setf (gethash checksum checksum-table)
+                                      (append (gethash checksum 
checksum-table) (list f)))))
+           (cl-loop for checksum being the hash-key in checksum-table using 
(hash-value same-files)
+                    when (< (length same-files) 2) do
+                    (remhash checksum checksum-table))
+           (cl-return checksum-table)))
+
+(defun find-dupes--generate-dired-list (&optional directories)
+  "Generate a list of grouped duplicate files, separated by a
+separator file specified by `find-dupes-separator-file'."
+  (cl-loop with dupes-table = (find-dupes--duplicate-files (or directories
+                                                           
find-dupes-directories))
+           for files being the hash-values in dupes-table
+           appending (append files (list find-dupes-separator-file))))
+
+(defun find-dupes-revert-function (&optional arg noconfirm)
+  "Revert function used instead of `dired-revert' for dired buffers generated 
by find-dupes."
+  (setq-local dired-directory
+              (append (list (first dired-directory))
+                      (find-dupes--generate-dired-list)))
+  (find-dupes--ensure-separator-file)
+  (dired-revert)
+  (find-dupes--remove-separator-file))
+
+(defun find-dupes-dired (directories)
+  "Find a list of duplicate files inside one or more directories
+and show them in a dired buffer."
+  (interactive "f")
+  (let ((default-directory "/"))
+    (find-dupes--ensure-separator-file)
+    (dired (cons "/" (find-dupes--generate-dired-list directories)))
+    (setq-local find-dupes-directories directories)
+    (setq-local revert-buffer-function 'find-dupes-revert-function)
+    (find-dupes--remove-separator-file)))
+
+;;;; Tests
+;; (find-dupes-checksum-file "~/tmp/my-file")
+;; (find-dupes--duplicate-files "~/my-dir")
+;; (find-dupes-dired "~/my-dir")
+
+(provide 'find-dupes-dired)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]