]> git.eshelyaron.com Git - emacs.git/commitdiff
Read mailcaps again only when necessary
authorGregory Heytings <gregory@heytings.org>
Mon, 1 Nov 2021 13:51:57 +0000 (14:51 +0100)
committerLars Ingebrigtsen <larsi@gnus.org>
Mon, 1 Nov 2021 13:51:57 +0000 (14:51 +0100)
* doc/lispref/files.texi (File Attributes): Document it.

* lisp/files.el (file-has-changed-p): New function.
(file-has-changed-p--hash-table): Internal variable used by the
new function (bug#51523).
* lisp/emacs-lisp/shortdoc.el (file): Mention it.

* lisp/net/mailcap.el (mailcap-parse-mailcaps): Read mailcaps again
only when at least one of the mailcap files has changed.  Fixes
bug#51523.

doc/lispref/files.texi
etc/NEWS
lisp/emacs-lisp/shortdoc.el
lisp/files.el
lisp/net/mailcap.el

index 59e18b32c2e4286f07957f74e48aebc0290aaa4f..250f7a3f9f5a94566806842e0424267b034edf39 100644 (file)
@@ -1314,6 +1314,15 @@ on the 19th, @file{aug-20} was written on the 20th, and the file
 @end example
 @end defun
 
+@defun file-has-changed-p filename
+This convenience function is useful when, for instance, parsing files
+run-time, and you typically want to re-read a file when it has
+changed.  This function returns non-@code{nil} the first time it's
+called on @var{filename} in an Emacs session, but will return
+@code{nil} on subsequent calls in that session (unless the file
+changes its modification time).
+@end defun
+
 @defun file-attributes filename &optional id-format
 @anchor{Definition of file-attributes}
 This function returns a list of attributes of file @var{filename}.  If
index 57c64f7cadbb214cb924a7106a28d40cbc8b8672..62cfb79a2ab1ca34c1473c708e93a8faebbcd201 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -360,6 +360,11 @@ Use 'exif-parse-file' and 'exif-field' instead.
 \f
 * Lisp Changes in Emacs 29.1
 
+*** New function 'file-has-changed-p'.
+This convenience function is useful when writing code that parses
+files run-time, and allows you to easily re-parse files when they have
+changed (but not otherwise).
+
 ---
 *** New function 'font-has-char-p'.
 This can be used to check whether a specific font has a glyph for a
index daf362dd88b274e0abea8cc62a9b5a2765273f99..c3d6c7429403f3179b41cb912943ba94c81ddb75 100644 (file)
@@ -358,6 +358,9 @@ There can be any number of :example/:result elements."
   (file-newer-than-file-p
    :no-eval (file-newer-than-file-p "/tmp/foo" "/tmp/bar")
    :eg-result nil)
+  (file-has-changed-p
+   :no-eval (file-has-changed-p "/tmp/foo")
+   :eg-result t)
   (file-equal-p
    :no-eval (file-equal-p "/tmp/foo" "/tmp/bar")
    :eg-result nil)
index 1e65d0ce835d2efee20f92834fb94c2ef13a140a..5e7be3844ebcf800eb7ca2163731affde6a4ace4 100644 (file)
@@ -6181,6 +6181,22 @@ Return nil if DIR is not an existing directory."
          (unless mismatch
            (file-equal-p root dir)))))))
 
+(defvar file-has-changed-p--hash-table (make-hash-table)
+  "Internal variable used by `file-has-changed-p'.")
+
+(defun file-has-changed-p (file)
+  "Return non-nil if FILE has changed.
+The modification time of FILE is compared to the modification
+time of FILE during a previous invocation of `file-has-changed-p'.
+Therefore the first invocation of `file-has-changed-p' always
+returns non-nil."
+  (let* ((attr (file-attributes file 'integer))
+         (mtime (file-attribute-modification-time attr))
+         (saved-mtime (gethash (intern file)
+                               file-has-changed-p--hash-table)))
+     (when (not (equal mtime saved-mtime))
+       (puthash (intern file) mtime file-has-changed-p--hash-table))))
+
 (defun copy-directory (directory newname &optional keep-time parents copy-contents)
   "Copy DIRECTORY to NEWNAME.  Both args must be strings.
 This function always sets the file modes of the output files to match
index 83d0eeef9f1ce41653a2ce3828b3e6fa627f698f..4dedd38c22c02818d2c51fc5b137403442d11ea0 100644 (file)
@@ -447,18 +447,19 @@ MAILCAPS if set; otherwise (on Unix) use the path from RFC 1524, plus
               ("/etc/mailcap" system)
               ("/usr/etc/mailcap" system)
              ("/usr/local/etc/mailcap" system)))))
-    ;; The ~/.mailcap entries will end up first in the resulting data.
-    (dolist (spec (reverse
-                   (if (stringp path)
-                       (split-string path path-separator t)
-                     path)))
-      (let ((source (and (consp spec) (cadr spec)))
-            (file-name (if (stringp spec)
-                           spec
-                         (car spec))))
-        (when (and (file-readable-p file-name)
-                   (file-regular-p file-name))
-          (mailcap-parse-mailcap file-name source))))
+    (when (seq-some (lambda (f) (file-has-changed-p (car f))) path)
+      ;; The ~/.mailcap entries will end up first in the resulting data.
+      (dolist (spec (reverse
+                    (if (stringp path)
+                        (split-string path path-separator t)
+                      path)))
+       (let ((source (and (consp spec) (cadr spec)))
+             (file-name (if (stringp spec)
+                            spec
+                          (car spec))))
+         (when (and (file-readable-p file-name)
+                    (file-regular-p file-name))
+           (mailcap-parse-mailcap file-name source)))))
     (setq mailcap-parsed-p t)))
 
 (defun mailcap-parse-mailcap (fname &optional source)