]> git.eshelyaron.com Git - emacs.git/commitdiff
autorevert: Resume with polling if file is deleted
authorMichael Albinus <michael.albinus@gmx.de>
Tue, 19 Apr 2016 09:05:55 +0000 (11:05 +0200)
committerMichael Albinus <michael.albinus@gmx.de>
Tue, 19 Apr 2016 09:05:55 +0000 (11:05 +0200)
* lisp/autorevert.el: Use consistent wording in comments and
docstrings.
(auto-revert-mode): Add local function to `kill-buffer-hook'.
(auto-revert-notify-handler): Improve handling of `stopped' event.

* test/lisp/autorevert-tests.el
(auto-revert-test02-auto-revert-deleted-file): New test.
(auto-revert-test03-auto-revert-tail-mode)
(auto-revert-test04-auto-revert-mode-dired): Rename them.

lisp/autorevert.el
test/lisp/autorevert-tests.el

index bc9d58e1a00eaae597506d2756dfa4ea5e8cc021..1129af8a2fa06a81f7e48952d9da829998025d5a 100644 (file)
 ;; Emacs.  You should never even notice that this package is active
 ;; (except that your buffers will be reverted, of course).
 ;;
+;; If the file exists, Auto-Revert Mode updates the buffer based on
+;; its (possibly empty) contents.  If the file no longer exists, then
+;; there is nothing to revert, so it does not modify the buffer.  Once
+;; a deleted file corresponding to a buffer in Auto-Revert Mode
+;; reappears, Auto-Revert Mode continues to work.
+;;
 ;; If Emacs is compiled with file notification support, notifications
 ;; are used instead of checking the time stamp of the files.  You can
 ;; disable this by setting the user option `auto-revert-use-notify' to
 ;; excluded from file notifications can be specified by
 ;; `auto-revert-notify-exclude-dir-regexp'.
 ;;
-;; After reverting a file buffer, Auto Revert Mode normally puts point
+;; After reverting a file buffer, Auto-Revert Mode normally puts point
 ;; at the same position that a regular manual revert would.  However,
 ;; there is one exception to this rule.  If point is at the end of the
 ;; buffer before reverting, it stays at the end.  Similarly if point
 ;; is displayed at the end of a file buffer in any window, it will stay
 ;; at the end of the buffer in that window, even if the window is not
-;; selected.  This way, you can use Auto Revert Mode to `tail' a file.
+;; selected.  This way, you can use Auto-Revert Mode to `tail' a file.
 ;; Just put point at the end of the buffer and it will stay there.
 ;; These rules apply to file buffers. For non-file buffers, the
 ;; behavior may be mode dependent.
 ;;
-;; While you can use Auto Revert Mode to tail a file, this package
-;; contains a third minor mode, Auto Revert Tail Mode, which does so
+;; While you can use Auto-Revert Mode to tail a file, this package
+;; contains a third minor mode, Auto-Revert Tail Mode, which does so
 ;; more efficiently, as long as you are sure that the file will only
 ;; change by growing at the end.  It only appends the new output,
 ;; instead of reverting the entire buffer.  It does so even if the
 
 (defgroup auto-revert nil
   "Revert individual buffers when files on disk change.
-Auto-Revert mode enables auto-revert in individual buffers.
-Global Auto-Revert mode does so in all buffers."
+Auto-Revert Mode enables auto-revert in individual buffers.
+Global Auto-Revert Mode does so in all buffers."
   :group 'files
   :group 'convenience)
 
@@ -144,7 +150,7 @@ If a timer is already active, there are two ways to make sure
 that the new value will take effect immediately.  You can set
 this variable through Custom or you can call the command
 `auto-revert-set-timer' after setting the variable.  Otherwise,
-the new value will take effect the first time Auto Revert Mode
+the new value will take effect the first time Auto-Revert Mode
 calls `auto-revert-set-timer' for internal reasons or in your
 next editing session."
   :group 'auto-revert
@@ -176,7 +182,7 @@ When non-nil, a message is generated whenever a file is reverted."
   "String to display in the mode line when Auto-Revert Mode is active.
 
 \(When the string is not empty, make sure that it has a leading space.)"
-  :tag "Auto Revert Mode Text"         ; To separate it from `global-...'
+  :tag "Auto-Revert Mode Text"         ; To separate it from `global-...'
   :group 'auto-revert
   :type 'string)
 
@@ -190,7 +196,7 @@ When non-nil, a message is generated whenever a file is reverted."
 
 (defcustom auto-revert-mode-hook nil
   "Functions to run when Auto-Revert Mode is activated."
-  :tag "Auto Revert Mode Hook"         ; To separate it from `global-...'
+  :tag "Auto-Revert Mode Hook"         ; To separate it from `global-...'
   :group 'auto-revert
   :type 'hook)
 
@@ -209,11 +215,11 @@ would only waste precious space."
   :type 'hook)
 
 (defcustom global-auto-revert-non-file-buffers nil
-  "When nil, Global Auto-Revert mode operates only on file-visiting buffers.
+  "When nil, Global Auto-Revert Mode operates only on file-visiting buffers.
 
 When non-nil, both file buffers and buffers with a custom
 `revert-buffer-function' and a `buffer-stale-function' are
-reverted by Global Auto-Revert mode.  These include the Buffer
+reverted by Global Auto-Revert Mode.  These include the Buffer
 List buffer displayed by `buffer-menu', and Dired buffers showing
 complete local directories.  The Buffer List buffer reverts every
 `auto-revert-interval' seconds; Dired buffers when the file list of
@@ -240,8 +246,8 @@ For more information, see Info node `(emacs)Autorevert'."
   :type 'hook)
 
 (defcustom auto-revert-check-vc-info nil
-  "If non-nil Auto Revert Mode reliably updates version control info.
-Auto Revert Mode updates version control info whenever the buffer
+  "If non-nil Auto-Revert Mode reliably updates version control info.
+Auto-Revert Mode updates version control info whenever the buffer
 needs reverting, regardless of the value of this variable.
 However, the version control state can change without changes to
 the work file.  If the change is made from the current Emacs
@@ -271,7 +277,7 @@ This variable becomes buffer local when set in any fashion.")
   :version "24.4")
 
 (defcustom auto-revert-use-notify t
-  "If non-nil Auto Revert Mode uses file notification functions.
+  "If non-nil Auto-Revert Mode uses file notification functions.
 You should set this variable through Custom."
   :group 'auto-revert
   :type 'boolean
@@ -337,12 +343,12 @@ This has been reported by a file notification event.")
 
 ;;;###autoload
 (define-minor-mode auto-revert-mode
-  "Toggle reverting buffer when the file changes (Auto Revert mode).
-With a prefix argument ARG, enable Auto Revert mode if ARG is
+  "Toggle reverting buffer when the file changes (Auto-Revert Mode).
+With a prefix argument ARG, enable Auto-Revert Mode if ARG is
 positive, and disable it otherwise.  If called from Lisp, enable
 the mode if ARG is omitted or nil.
 
-Auto Revert mode is a minor mode that affects only the current
+Auto-Revert Mode is a minor mode that affects only the current
 buffer.  When enabled, it reverts the buffer when the file on
 disk changes.
 
@@ -351,8 +357,14 @@ Use `auto-revert-tail-mode' if you know that the file will only grow
 without being changed in the part that is already in the buffer."
   :group 'auto-revert :lighter auto-revert-mode-text
   (if auto-revert-mode
-      (if (not (memq (current-buffer) auto-revert-buffer-list))
-         (push (current-buffer) auto-revert-buffer-list))
+      (when (not (memq (current-buffer) auto-revert-buffer-list))
+        (push (current-buffer) auto-revert-buffer-list)
+        (add-hook
+         'kill-buffer-hook
+         (lambda ()
+           (setq auto-revert-buffer-list
+                 (delq (current-buffer) auto-revert-buffer-list)))
+         nil t))
     (when auto-revert-use-notify (auto-revert-notify-rm-watch))
     (setq auto-revert-buffer-list
          (delq (current-buffer) auto-revert-buffer-list)))
@@ -374,11 +386,11 @@ This function is designed to be added to hooks, for example:
 ;;;###autoload
 (define-minor-mode auto-revert-tail-mode
   "Toggle reverting tail of buffer when the file grows.
-With a prefix argument ARG, enable Auto-Revert Tail mode if ARG
+With a prefix argument ARG, enable Auto-Revert Tail Mode if ARG
 is positive, and disable it otherwise.  If called from Lisp,
 enable the mode if ARG is omitted or nil.
 
-When Auto Revert Tail mode is enabled, the tail of the file is
+When Auto-Revert Tail Mode is enabled, the tail of the file is
 constantly followed, as with the shell command `tail -f'.  This
 means that whenever the file grows on disk (presumably because
 some background process is appending to it from time to time),
@@ -428,7 +440,7 @@ Perform a full revert? ")
 
 ;;;###autoload
 (defun turn-on-auto-revert-tail-mode ()
-  "Turn on Auto-Revert Tail mode.
+  "Turn on Auto-Revert Tail Mode.
 
 This function is designed to be added to hooks, for example:
   (add-hook \\='my-logfile-mode-hook #\\='turn-on-auto-revert-tail-mode)"
@@ -437,12 +449,12 @@ This function is designed to be added to hooks, for example:
 
 ;;;###autoload
 (define-minor-mode global-auto-revert-mode
-  "Toggle Global Auto Revert mode.
-With a prefix argument ARG, enable Global Auto Revert mode if ARG
+  "Toggle Global Auto-Revert Mode.
+With a prefix argument ARG, enable Global Auto-Revert Mode if ARG
 is positive, and disable it otherwise.  If called from Lisp,
 enable the mode if ARG is omitted or nil.
 
-Global Auto Revert mode is a global minor mode that reverts any
+Global Auto-Revert Mode is a global minor mode that reverts any
 buffer associated with a file when the file changes on disk.  Use
 `auto-revert-mode' to revert a particular buffer.
 
@@ -573,16 +585,19 @@ no more reverts are possible until the next call of
 
       (if (eq action 'stopped)
           ;; File notification has stopped.  Continue with polling.
-          (cl-dolist (buffer buffers)
+          (cl-dolist (buffer
+                      (if global-auto-revert-mode
+                          (buffer-list) auto-revert-buffer-list))
             (with-current-buffer buffer
-              (when (or
-                     ;; A buffer associated with a file.
-                     (and (stringp buffer-file-name)
-                          (string-equal
-                           (file-name-nondirectory file)
-                           (file-name-nondirectory buffer-file-name)))
-                     ;; A buffer w/o a file, like dired.
-                     (null buffer-file-name))
+              (when (and (equal descriptor auto-revert-notify-watch-descriptor)
+                         (or
+                          ;; A buffer associated with a file.
+                          (and (stringp buffer-file-name)
+                               (string-equal
+                                (file-name-nondirectory file)
+                                (file-name-nondirectory buffer-file-name)))
+                          ;; A buffer w/o a file, like dired.
+                          (null buffer-file-name)))
                 (auto-revert-notify-rm-watch)
                 (setq-local auto-revert-use-notify nil))))
 
@@ -736,7 +751,7 @@ To avoid starvation, the buffers in `auto-revert-remaining-buffers'
 are checked first the next time this function is called.
 
 This function is also responsible for removing buffers no longer in
-Auto-Revert mode from `auto-revert-buffer-list', and for canceling
+Auto-Revert Mode from `auto-revert-buffer-list', and for canceling
 the timer when no buffers need to be checked."
 
   (setq auto-revert-buffers-counter
index a6f8cb29563fa5a6da59889b10b446a392390036..2f951c0c9aa67432bf8531373d27f22ab4a8029c 100644 (file)
       (ignore-errors (delete-directory tmpdir1 'recursive))
       (ignore-errors (delete-directory tmpdir2 'recursive)))))
 
-(ert-deftest auto-revert-test02-auto-revert-tail-mode ()
+;; This is inspired by Bug#23276.
+(ert-deftest auto-revert-test02-auto-revert-deleted-file ()
+  "Check autorevert for a deleted file."
+  :tags '(:expensive-test)
+
+  (let ((tmpfile (make-temp-file "auto-revert-test"))
+        buf)
+    (unwind-protect
+       (progn
+          (with-current-buffer (get-buffer-create "*Messages*")
+            (narrow-to-region (point-max) (point-max)))
+          (write-region "any text" nil tmpfile nil 'no-message)
+         (setq buf (find-file-noselect tmpfile))
+         (with-current-buffer buf
+            (should (string-equal (buffer-string) "any text"))
+            ;; `buffer-stale--default-function' checks for
+            ;; `verify-visited-file-modtime'.  We must ensure that
+            ;; it returns nil.
+            (sleep-for 1)
+            (auto-revert-mode 1)
+            (should auto-revert-mode)
+
+            ;; Remove file while reverting.  We simulate this by
+            ;; modifying `before-revert-hook'.
+            (add-hook
+             'before-revert-hook
+             (lambda () (delete-file buffer-file-name))
+             nil t)
+            (with-current-buffer (get-buffer-create "*Messages*")
+              (narrow-to-region (point-max) (point-max)))
+           (sleep-for 1)
+            (write-region "another text" nil tmpfile nil 'no-message)
+
+           ;; Check, that the buffer hasn't been reverted.  File
+           ;; notification should be disabled, falling back to
+           ;; polling.
+            (auto-revert--wait-for-revert buf)
+            (should (string-match "any text" (buffer-string)))
+            (should-not auto-revert-use-notify)
+
+            ;; Once the file has been recreated, the buffer shall be
+            ;; reverted.
+            (kill-local-variable 'before-revert-hook)
+            (with-current-buffer (get-buffer-create "*Messages*")
+              (narrow-to-region (point-max) (point-max)))
+           (sleep-for 1)
+            (write-region "another text" nil tmpfile nil 'no-message)
+
+           ;; Check, that the buffer has been reverted.
+            (auto-revert--wait-for-revert buf)
+            (should (string-match "another text" (buffer-string)))
+
+            ;; An empty file shall still be reverted.
+            (with-current-buffer (get-buffer-create "*Messages*")
+              (narrow-to-region (point-max) (point-max)))
+           (sleep-for 1)
+            (write-region "" nil tmpfile nil 'no-message)
+
+           ;; Check, that the buffer has been reverted.
+            (auto-revert--wait-for-revert buf)
+            (should (string-equal "" (buffer-string)))))
+
+      ;; Exit.
+      (with-current-buffer "*Messages*" (widen))
+      (ignore-errors
+        (with-current-buffer buf (set-buffer-modified-p nil))
+        (kill-buffer buf))
+      (ignore-errors (delete-file tmpfile)))))
+
+(ert-deftest auto-revert-test03-auto-revert-tail-mode ()
   "Check autorevert tail mode."
   ;; `auto-revert-buffers' runs every 5".  And we must wait, until the
   ;; file has been reverted.
       (ignore-errors (kill-buffer buf))
       (ignore-errors (delete-file tmpfile)))))
 
-(ert-deftest auto-revert-test03-auto-revert-mode-dired ()
+(ert-deftest auto-revert-test04-auto-revert-mode-dired ()
   "Check autorevert for dired."
   ;; `auto-revert-buffers' runs every 5".  And we must wait, until the
   ;; file has been reverted.