Read mailcaps again only when necessary

* 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.
This commit is contained in:
Gregory Heytings 2021-11-01 14:51:57 +01:00 committed by Lars Ingebrigtsen
parent 453d104602
commit daea9b3b44
5 changed files with 46 additions and 12 deletions

View 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

View file

@ -360,6 +360,11 @@ Use 'exif-parse-file' and 'exif-field' instead.
* 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

View 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)

View 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

View 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)