all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Eli Zaretskii <eliz@gnu.org>
To: harmvegt@gmail.com
Cc: 72919-done@debbugs.gnu.org
Subject: bug#72919: 29.1; chart-space-usage in chart.el does not work correctly on windows
Date: Sat, 07 Sep 2024 12:24:21 +0300	[thread overview]
Message-ID: <86v7z7yfy2.fsf@gnu.org> (raw)
In-Reply-To: <86bk179q94.fsf@gnu.org> (message from Eli Zaretskii on Sun, 01 Sep 2024 21:35:03 +0300)

> Cc: 72919@debbugs.gnu.org
> Date: Sun, 01 Sep 2024 21:35:03 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> 
> > I've tried your changes with and without du. This uncovered something in the
> > original implementation, namely that the original implementation did not count
> > hidden files and directories. du * skips dotfiles for me.
> >
> > With du present chart-space-usage shows the lisp directory as the largest in the 
> > emacs repository root. Without du it shows .git as the largest.
> 
> This just means minor adjustments in the code I posted: we need to use
> a different regexp in the call to directory-files-recursively, and
> also ignore files that start with a dot in the command itself.  I will
> make those changes, thanks for pointing them out

Actually, there's more here than meets the eye.  'du' does NOT skip
dotfiles (unless instructed to do so via the --exclude= command-line
option).  What happens here is that a typical Unix shell does not
include dotfiles in the expansion of the "*" wildcard, so "du *" does
not count dotfiles, but only in the directory in which 'du' was
invoked; dotfiles in subdirectories _are_ counted.

I made the Lisp implementation skip dotfiles in the directory for
which the command is invoked, but not in the subdirectories.  Windows
users who do have 'du' installed will now depend on how "*" is
expanded, which is probably different in different ports of 'du'.  I
considered using --exclude=, but that would exclude dotfiles in
subdirectories as well, which is not what happens in the Unix case.

> I will post a version that ignores dotfiles.

I installed a modified version on the emacs-30 branch.  The patch is
below in case you want to try it.

With that, I'm closing this bug.

diff --git a/lisp/emacs-lisp/chart.el b/lisp/emacs-lisp/chart.el
index da61e45..2ca9b64 100644
--- a/lisp/emacs-lisp/chart.el
+++ b/lisp/emacs-lisp/chart.el
@@ -641,27 +641,68 @@ chart-file-count
 		       (lambda (a b) (> (cdr a) (cdr b))))
     ))
 
+;; This assumes 4KB blocks
+(defun chart--file-size (size)
+  (* (/ (+ size 4095) 4096) 4096))
+
+(defun chart--directory-size (dir)
+  "Compute total size of files in directory DIR and its subdirectories.
+DIR is assumed to be a directory, verified by the caller."
+  (let ((size 0))
+    (dolist (file (directory-files-recursively dir "." t))
+      (let ((fsize (nth 7 (file-attributes file))))
+        (if (> fsize 0)
+            (setq size
+                  (+ size (chart--file-size fsize))))))
+    size))
+
 (defun chart-space-usage (d)
   "Display a top usage chart for directory D."
   (interactive "DDirectory: ")
   (message "Collecting statistics...")
   (let ((nmlst nil)
 	(cntlst nil)
-	(b (get-buffer-create " *du-tmp*")))
-    (set-buffer b)
-    (erase-buffer)
-    (insert "cd " d ";du -sk * \n")
-    (message "Running `cd %s;du -sk *'..." d)
-    (call-process-region (point-min) (point-max) shell-file-name t
-			 (current-buffer) nil)
-    (goto-char (point-min))
-    (message "Scanning output ...")
-    (while (re-search-forward "^\\([0-9]+\\)[ \t]+\\([^ \n]+\\)$" nil t)
-      (let* ((nam (buffer-substring (match-beginning 2) (match-end 2)))
-	     (num (buffer-substring (match-beginning 1) (match-end 1))))
-	(setq nmlst (cons nam nmlst)
-	      ;; * 1000 to put it into bytes
-	      cntlst (cons (* (string-to-number num) 1000) cntlst))))
+        b)
+    (if (executable-find "du")
+        (progn
+	  (setq b (get-buffer-create " *du-tmp*"))
+          (set-buffer b)
+          (erase-buffer)
+          (if (and (memq system-type '(windows-nt ms-dos))
+                   (fboundp 'w32-shell-dos-semantics)
+                   (w32-shell-dos-semantics))
+              (progn
+                ;; With Windows shells, 'cd' does not change the drive,
+                ;; and ';' is not reliable for running multiple
+                ;; commands, so use alternatives.  We quote the
+                ;; directory because otherwise pushd will barf on a
+                ;; directory with forward slashes.  Note that * will not
+                ;; skip dotfiles with Windows shells, unlike on Unix.
+                (insert "pushd \"" d "\" && du -sk * \n")
+                (message "Running `pushd \"%s\" && du -sk *'..." d))
+            (insert "cd " d ";du -sk * \n")
+            (message "Running `cd %s;du -sk *'..." d))
+          (call-process-region (point-min) (point-max) shell-file-name t
+			       (current-buffer) nil)
+          (goto-char (point-min))
+          (message "Scanning output ...")
+          (while (re-search-forward "^\\([0-9]+\\)[ \t]+\\([^ \n]+\\)$" nil t)
+            (let* ((nam (buffer-substring (match-beginning 2) (match-end 2)))
+	           (num (buffer-substring (match-beginning 1) (match-end 1))))
+	      (setq nmlst (cons nam nmlst)
+	            ;; * 1000 to put it into bytes
+	            cntlst (cons (* (string-to-number num) 1000) cntlst)))))
+      (dolist (file (directory-files d t directory-files-no-dot-files-regexp))
+        (let ((fbase (file-name-nondirectory file)))
+          ;; Typical shells exclude files and subdirectories whose names
+          ;; begin with a period when it expands *, so we do the same.
+          (unless (string-match-p "\\`\\." fbase)
+            (setq nmlst (cons fbase nmlst))
+            (if (file-regular-p file)
+                (setq cntlst (cons (chart--file-size
+                                    (nth 7 (file-attributes file)))
+                                   cntlst))
+              (setq cntlst (cons (chart--directory-size file) cntlst)))))))
     (if (not nmlst)
 	(error "No files found!"))
     (chart-bar-quickie 'vertical (format "Largest files in %s" d)





      parent reply	other threads:[~2024-09-07  9:24 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-31 18:52 bug#72919: 29.1; chart-space-usage in chart.el does not work correctly on windows Harm Van der Vegt
2024-09-01  8:13 ` Eli Zaretskii
     [not found]   ` <CAPdXVSxuhccEEYSLH+WR57irNYn4OrWWhmPPcCY5GjPa-RTnHQ@mail.gmail.com>
2024-09-01 18:16     ` bug#72919: Fwd: " Harm Van der Vegt
2024-09-01 18:35     ` Eli Zaretskii
2024-09-01 19:06       ` Harm Van der Vegt
2024-09-07  9:24       ` Eli Zaretskii [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=86v7z7yfy2.fsf@gnu.org \
    --to=eliz@gnu.org \
    --cc=72919-done@debbugs.gnu.org \
    --cc=harmvegt@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.