aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2024-09-07 12:17:24 +0300
committerEli Zaretskii2024-09-07 12:17:24 +0300
commite1304e9b1bbb62ff3e3680c84bd1fad4922b41eb (patch)
tree5e4daa49ffde16c7ddc209752ac23b1379b4d7d8
parent04c44405bf604380c575fa2a4d9611af0f3bc0d9 (diff)
downloademacs-e1304e9b1bbb62ff3e3680c84bd1fad4922b41eb.tar.gz
emacs-e1304e9b1bbb62ff3e3680c84bd1fad4922b41eb.zip
Fix 'chart-space-usage' on MS-Windows
* lisp/emacs-lisp/chart.el (chart--file-size) (chart--directory-size): New functions. (chart-space-usage): Invoke 'du' correctly on MS-Windows. Provide alternative implementation in Lisp when 'du' is not installed, using 'chart--directory-size' and 'chart--file-size'. (Bug#72919)
-rw-r--r--lisp/emacs-lisp/chart.el71
1 files changed, 56 insertions, 15 deletions
diff --git a/lisp/emacs-lisp/chart.el b/lisp/emacs-lisp/chart.el
index da61e45213d..2ca9b64be33 100644
--- a/lisp/emacs-lisp/chart.el
+++ b/lisp/emacs-lisp/chart.el
@@ -641,27 +641,68 @@ SORT-PRED if desired."
641 (lambda (a b) (> (cdr a) (cdr b)))) 641 (lambda (a b) (> (cdr a) (cdr b))))
642 )) 642 ))
643 643
644;; This assumes 4KB blocks
645(defun chart--file-size (size)
646 (* (/ (+ size 4095) 4096) 4096))
647
648(defun chart--directory-size (dir)
649 "Compute total size of files in directory DIR and its subdirectories.
650DIR is assumed to be a directory, verified by the caller."
651 (let ((size 0))
652 (dolist (file (directory-files-recursively dir "." t))
653 (let ((fsize (nth 7 (file-attributes file))))
654 (if (> fsize 0)
655 (setq size
656 (+ size (chart--file-size fsize))))))
657 size))
658
644(defun chart-space-usage (d) 659(defun chart-space-usage (d)
645 "Display a top usage chart for directory D." 660 "Display a top usage chart for directory D."
646 (interactive "DDirectory: ") 661 (interactive "DDirectory: ")
647 (message "Collecting statistics...") 662 (message "Collecting statistics...")
648 (let ((nmlst nil) 663 (let ((nmlst nil)
649 (cntlst nil) 664 (cntlst nil)
650 (b (get-buffer-create " *du-tmp*"))) 665 b)
651 (set-buffer b) 666 (if (executable-find "du")
652 (erase-buffer) 667 (progn
653 (insert "cd " d ";du -sk * \n") 668 (setq b (get-buffer-create " *du-tmp*"))
654 (message "Running `cd %s;du -sk *'..." d) 669 (set-buffer b)
655 (call-process-region (point-min) (point-max) shell-file-name t 670 (erase-buffer)
656 (current-buffer) nil) 671 (if (and (memq system-type '(windows-nt ms-dos))
657 (goto-char (point-min)) 672 (fboundp 'w32-shell-dos-semantics)
658 (message "Scanning output ...") 673 (w32-shell-dos-semantics))
659 (while (re-search-forward "^\\([0-9]+\\)[ \t]+\\([^ \n]+\\)$" nil t) 674 (progn
660 (let* ((nam (buffer-substring (match-beginning 2) (match-end 2))) 675 ;; With Windows shells, 'cd' does not change the drive,
661 (num (buffer-substring (match-beginning 1) (match-end 1)))) 676 ;; and ';' is not reliable for running multiple
662 (setq nmlst (cons nam nmlst) 677 ;; commands, so use alternatives. We quote the
663 ;; * 1000 to put it into bytes 678 ;; directory because otherwise pushd will barf on a
664 cntlst (cons (* (string-to-number num) 1000) cntlst)))) 679 ;; directory with forward slashes. Note that * will not
680 ;; skip dotfiles with Windows shells, unlike on Unix.
681 (insert "pushd \"" d "\" && du -sk * \n")
682 (message "Running `pushd \"%s\" && du -sk *'..." d))
683 (insert "cd " d ";du -sk * \n")
684 (message "Running `cd %s;du -sk *'..." d))
685 (call-process-region (point-min) (point-max) shell-file-name t
686 (current-buffer) nil)
687 (goto-char (point-min))
688 (message "Scanning output ...")
689 (while (re-search-forward "^\\([0-9]+\\)[ \t]+\\([^ \n]+\\)$" nil t)
690 (let* ((nam (buffer-substring (match-beginning 2) (match-end 2)))
691 (num (buffer-substring (match-beginning 1) (match-end 1))))
692 (setq nmlst (cons nam nmlst)
693 ;; * 1000 to put it into bytes
694 cntlst (cons (* (string-to-number num) 1000) cntlst)))))
695 (dolist (file (directory-files d t directory-files-no-dot-files-regexp))
696 (let ((fbase (file-name-nondirectory file)))
697 ;; Typical shells exclude files and subdirectories whose names
698 ;; begin with a period when it expands *, so we do the same.
699 (unless (string-match-p "\\`\\." fbase)
700 (setq nmlst (cons fbase nmlst))
701 (if (file-regular-p file)
702 (setq cntlst (cons (chart--file-size
703 (nth 7 (file-attributes file)))
704 cntlst))
705 (setq cntlst (cons (chart--directory-size file) cntlst)))))))
665 (if (not nmlst) 706 (if (not nmlst)
666 (error "No files found!")) 707 (error "No files found!"))
667 (chart-bar-quickie 'vertical (format "Largest files in %s" d) 708 (chart-bar-quickie 'vertical (format "Largest files in %s" d)