Commit 864c58ca authored by Michael Albinus's avatar Michael Albinus

* filenotify.el: New package.

* autorevert.el (top): Require filenotify.el.
(auto-revert-notify-enabled): Remove.  Use `file-notify-support'
instead.
(auto-revert-notify-rm-watch, auto-revert-notify-add-watch)
(auto-revert-notify-handler): Use `file-notify-*' functions.

* subr.el (file-notify-handle-event): Move function to filenotify.el.

* net/tramp.el (tramp-file-name-for-operation): Handle
`file-notify-add-watch' and `file-notify-rm-watch'.

* net/tramp-sh.el (tramp-sh-file-name-handler-alist): Add handler
for `file-notify-add-watch' and `file-notify-rm-watch'.
(tramp-process-sentinel): Improve trace.
(tramp-sh-handle-file-notify-add-watch)
(tramp-sh-file-notify-process-filter)
(tramp-sh-handle-file-notify-rm-watch)
(tramp-get-remote-inotifywait): New defuns.
parent 86dfb7a8
2013-07-04 Michael Albinus <michael.albinus@gmx.de>
* filenotify.el: New package.
* autorevert.el (top): Require filenotify.el.
(auto-revert-notify-enabled): Remove. Use `file-notify-support'
instead.
(auto-revert-notify-rm-watch, auto-revert-notify-add-watch)
(auto-revert-notify-handler): Use `file-notify-*' functions.
* subr.el (file-notify-handle-event): Move function to filenotify.el.
* net/tramp.el (tramp-file-name-for-operation): Handle
`file-notify-add-watch' and `file-notify-rm-watch'.
* net/tramp-sh.el (tramp-sh-file-name-handler-alist): Add handler
for `file-notify-add-watch' and `file-notify-rm-watch'.
(tramp-process-sentinel): Improve trace.
(tramp-sh-handle-file-notify-add-watch)
(tramp-sh-file-notify-process-filter)
(tramp-sh-handle-file-notify-rm-watch)
(tramp-get-remote-inotifywait): New defuns.
2013-07-03 Juri Linkov <juri@jurta.org>
* buff-menu.el (Buffer-menu-multi-occur): Add args and move the
......@@ -299,12 +322,12 @@
2013-06-25 Rüdiger Sonderfeld <ruediger@c-plusplus.de>
* lisp/textmodes/bibtex.el (bibtex-generate-url-list): Add support
* textmodes/bibtex.el (bibtex-generate-url-list): Add support
for DOI URLs.
2013-06-25 Rüdiger Sonderfeld <ruediger@c-plusplus.de>
* lisp/textmodes/bibtex.el (bibtex-mode, bibtex-set-dialect):
* textmodes/bibtex.el (bibtex-mode, bibtex-set-dialect):
Update imenu-support when dialect changes.
2013-06-25 Leo Liu <sdl.web@gmail.com>
......
......@@ -103,6 +103,7 @@
(eval-when-compile (require 'cl-lib))
(require 'timer)
(require 'filenotify)
;; Custom Group:
;;
......@@ -270,21 +271,17 @@ This variable becomes buffer local when set in any fashion.")
:type 'boolean
:version "24.4")
(defconst auto-revert-notify-enabled
(or (featurep 'gfilenotify) (featurep 'inotify) (featurep 'w32notify))
"Non-nil when Emacs has been compiled with file notification support.")
(defcustom auto-revert-use-notify auto-revert-notify-enabled
(defcustom auto-revert-use-notify (and file-notify-support t)
"If non-nil Auto Revert Mode uses file notification functions.
This requires Emacs being compiled with file notification
support (see `auto-revert-notify-enabled'). You should set this
variable through Custom."
support (see `file-notify-support'). You should set this variable
through Custom."
:group 'auto-revert
:type 'boolean
:set (lambda (variable value)
(set-default variable (and auto-revert-notify-enabled value))
(set-default variable (and file-notify-support value))
(unless (symbol-value variable)
(when auto-revert-notify-enabled
(when file-notify-support
(dolist (buf (buffer-list))
(with-current-buffer buf
(when (symbol-value 'auto-revert-notify-watch-descriptor)
......@@ -502,12 +499,7 @@ will use an up-to-date value of `auto-revert-interval'"
(puthash key value auto-revert-notify-watch-descriptor-hash-list)
(remhash key auto-revert-notify-watch-descriptor-hash-list)
(ignore-errors
(funcall
(cond
((fboundp 'gfile-rm-watch) 'gfile-rm-watch)
((fboundp 'inotify-rm-watch) 'inotify-rm-watch)
((fboundp 'w32notify-rm-watch) 'w32notify-rm-watch))
auto-revert-notify-watch-descriptor)))))
(file-notify-rm-watch auto-revert-notify-watch-descriptor)))))
auto-revert-notify-watch-descriptor-hash-list)
(remove-hook 'kill-buffer-hook 'auto-revert-notify-rm-watch))
(setq auto-revert-notify-watch-descriptor nil
......@@ -522,100 +514,58 @@ will use an up-to-date value of `auto-revert-interval'"
(when (and buffer-file-name auto-revert-use-notify
(not auto-revert-notify-watch-descriptor))
(let ((func
(cond
((fboundp 'gfile-add-watch) 'gfile-add-watch)
((fboundp 'inotify-add-watch) 'inotify-add-watch)
((fboundp 'w32notify-add-watch) 'w32notify-add-watch)))
(aspect
(cond
((fboundp 'gfile-add-watch) '(watch-mounts))
;; `attrib' is needed for file modification time.
((fboundp 'inotify-add-watch) '(attrib create modify moved-to))
((fboundp 'w32notify-add-watch) '(size last-write-time))))
(file (if (or (fboundp 'gfile-add-watch) (fboundp 'inotify-add-watch))
(directory-file-name (expand-file-name default-directory))
(buffer-file-name))))
(setq auto-revert-notify-watch-descriptor
(ignore-errors
(funcall func file aspect 'auto-revert-notify-handler)))
(if auto-revert-notify-watch-descriptor
(progn
(puthash
auto-revert-notify-watch-descriptor
(cons (current-buffer)
(gethash auto-revert-notify-watch-descriptor
auto-revert-notify-watch-descriptor-hash-list))
auto-revert-notify-watch-descriptor-hash-list)
(add-hook (make-local-variable 'kill-buffer-hook)
'auto-revert-notify-rm-watch))
;; Fallback to file checks.
(set (make-local-variable 'auto-revert-use-notify) nil)))))
(defun auto-revert-notify-event-p (event)
"Check that event is a file notification event."
(and (listp event)
(cond ((featurep 'gfilenotify)
(and (>= (length event) 3) (stringp (nth 2 event))))
((featurep 'inotify)
(= (length event) 4))
((featurep 'w32notify)
(and (= (length event) 3) (stringp (nth 2 event)))))))
(defun auto-revert-notify-event-descriptor (event)
"Return watch descriptor of file notification event, or nil."
(and (auto-revert-notify-event-p event) (car event)))
(defun auto-revert-notify-event-action (event)
"Return action of file notification event, or nil."
(and (auto-revert-notify-event-p event) (nth 1 event)))
(defun auto-revert-notify-event-file-name (event)
"Return file name of file notification event, or nil."
(and (auto-revert-notify-event-p event)
(cond ((featurep 'gfilenotify) (nth 2 event))
((featurep 'inotify) (nth 3 event))
((featurep 'w32notify) (nth 2 event)))))
(setq auto-revert-notify-watch-descriptor
(ignore-errors
(file-notify-add-watch
(expand-file-name buffer-file-name default-directory)
'(change attribute-change) 'auto-revert-notify-handler)))
(if auto-revert-notify-watch-descriptor
(progn
(puthash
auto-revert-notify-watch-descriptor
(cons (current-buffer)
(gethash auto-revert-notify-watch-descriptor
auto-revert-notify-watch-descriptor-hash-list))
auto-revert-notify-watch-descriptor-hash-list)
(add-hook (make-local-variable 'kill-buffer-hook)
'auto-revert-notify-rm-watch))
;; Fallback to file checks.
(set (make-local-variable 'auto-revert-use-notify) nil))))
(defun auto-revert-notify-handler (event)
"Handle an EVENT returned from file notification."
(when (auto-revert-notify-event-p event)
(let* ((descriptor (auto-revert-notify-event-descriptor event))
(action (auto-revert-notify-event-action event))
(file (auto-revert-notify-event-file-name event))
(ignore-errors
(let* ((descriptor (car event))
(action (nth 1 event))
(file (nth 2 event))
(file1 (nth 3 event)) ;; Target of `renamed'.
(buffers (gethash descriptor
auto-revert-notify-watch-descriptor-hash-list)))
(ignore-errors
;; Check, that event is meant for us.
;; TODO: Filter events which stop watching, like `move' or `removed'.
(cl-assert descriptor)
(cond
((featurep 'gfilenotify)
(cl-assert (memq action '(attribute-changed changed created deleted
;; FIXME: I keep getting this action, so I
;; added it here, but I have no idea what
;; I'm doing. --Stef
changes-done-hint))
t))
((featurep 'inotify)
(cl-assert (or (memq 'attrib action)
(memq 'create action)
(memq 'modify action)
(memq 'moved-to action))))
((featurep 'w32notify) (cl-assert (eq 'modified action))))
;; Since we watch a directory, a file name must be returned.
(cl-assert (stringp file))
(dolist (buffer buffers)
(when (buffer-live-p buffer)
(with-current-buffer buffer
(when (and (stringp buffer-file-name)
(string-equal
(file-name-nondirectory file)
(file-name-nondirectory buffer-file-name)))
;; Mark buffer modified.
(setq auto-revert-notify-modified-p t)
;; No need to check other buffers.
(cl-return)))))))))
;; Check, that event is meant for us.
(cl-assert descriptor)
;; We do not handle `deleted', because nothing has to be refreshed.
(cl-assert (memq action '(attribute-changed changed created renamed)) t)
;; Since we watch a directory, a file name must be returned.
(cl-assert (stringp file))
(when (eq action 'renamed) (cl-assert (stringp file1)))
;; Loop over all buffers, in order to find the intended one.
(dolist (buffer buffers)
(when (buffer-live-p buffer)
(with-current-buffer buffer
(when (and (stringp buffer-file-name)
(or
(and (memq action '(attribute-changed changed created))
(string-equal
(file-name-nondirectory file)
(file-name-nondirectory buffer-file-name)))
(and (eq action 'renamed)
(string-equal
(file-name-nondirectory file1)
(file-name-nondirectory buffer-file-name)))))
;; Mark buffer modified.
(setq auto-revert-notify-modified-p t)
;; No need to check other buffers.
(cl-return))))))))
(defun auto-revert-active-p ()
"Check if auto-revert is active (in current buffer or globally)."
......
This diff is collapsed.
......@@ -862,7 +862,9 @@ of command line.")
(set-file-selinux-context . tramp-sh-handle-set-file-selinux-context)
(file-acl . tramp-sh-handle-file-acl)
(set-file-acl . tramp-sh-handle-set-file-acl)
(vc-registered . tramp-sh-handle-vc-registered))
(vc-registered . tramp-sh-handle-vc-registered)
(file-notify-add-watch . tramp-sh-handle-file-notify-add-watch)
(file-notify-rm-watch . tramp-sh-handle-file-notify-rm-watch))
"Alist of handler functions.
Operations not mentioned here will be handled by the normal Emacs functions.")
......@@ -2669,7 +2671,7 @@ the result will be a local, non-Tramp, filename."
(unless (memq (process-status proc) '(run open))
(let ((vec (tramp-get-connection-property proc "vector" nil)))
(when vec
(tramp-message vec 5 "Sentinel called: `%s' `%s'" proc event)
(tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event)
(tramp-flush-connection-property proc)
(tramp-flush-directory-property vec "")))))
......@@ -3376,6 +3378,63 @@ Fall back to normal file name handler if no Tramp handler exists."
;; Default file name handlers, we don't care.
(t (tramp-run-real-handler operation args)))))))
;; We use inotify for implementation. It is more likely to exist than glib.
(defun tramp-sh-handle-file-notify-add-watch (file-name flags callback)
"Like `file-notify-add-watch' for Tramp files."
(setq file-name (expand-file-name file-name))
(with-parsed-tramp-file-name file-name nil
(let* ((default-directory (file-name-directory file-name))
(command (tramp-get-remote-inotifywait v))
(events
(cond
((and (memq 'change flags) (memq 'attribute-change flags))
"create,modify,move,delete,attrib")
((memq 'change flags) "create,modify,move,delete")
((memq 'attribute-change flags) "attrib")))
(p (and command
(start-file-process
"inotifywait" (generate-new-buffer " *inotifywait*")
command "-mq" "-e" events localname))))
;; Return the process object as watch-descriptor.
(if (not (processp p))
(tramp-error
v 'file-notify-error "`inotifywait' not found on remote host")
(tramp-compat-set-process-query-on-exit-flag p nil)
(set-process-filter p 'tramp-sh-file-notify-process-filter)
p))))
(defun tramp-sh-file-notify-process-filter (proc string)
"Read output from \"inotifywait\" and add corresponding file-notify events."
(tramp-message proc 6 (format "%S\n%s" proc string))
(dolist (line (split-string string "[\n\r]+" 'omit-nulls))
;; Check, whether there is a problem.
(unless
(string-match
"^[^[:blank:]]+[[:blank:]]+\\([^[:blank:]]+\\)+\\([[:blank:]]+\\([^[:blank:]]+\\)\\)?[[:blank:]]*$" line)
(tramp-error proc 'file-notify-error "%s" line))
;; Usually, we would add an Emacs event now. Unfortunately,
;; `unread-command-events' does not accept several events at once.
;; Therefore, we apply the callback directly.
(let* ((object
(list
proc
(mapcar
(lambda (x)
(intern-soft (replace-regexp-in-string "_" "-" (downcase x))))
(split-string (match-string 1 line) "," 'omit-nulls))
(match-string 3 line))))
(tramp-compat-funcall 'file-notify-callback object))))
(defvar file-notify-descriptors)
(defun tramp-sh-handle-file-notify-rm-watch (proc)
"Like `file-notify-rm-watch' for Tramp files."
;; The descriptor must be a process object.
(unless (and (processp proc) (gethash proc file-notify-descriptors))
(tramp-error proc 'file-notify-error "Not a valid descriptor %S" proc))
(tramp-message proc 6 (format "Kill %S" proc))
(kill-process proc))
;;; Internal Functions:
(defun tramp-maybe-send-script (vec script name)
......@@ -4864,6 +4923,11 @@ Return ATTR."
(tramp-message vec 5 "Finding a suitable `trash' command")
(tramp-find-executable vec "trash" (tramp-get-remote-path vec))))
(defun tramp-get-remote-inotifywait (vec)
(with-tramp-connection-property vec "inotifywait"
(tramp-message vec 5 "Finding a suitable `inotifywait' command")
(tramp-find-executable vec "inotifywait" (tramp-get-remote-path vec) t t)))
(defun tramp-get-remote-id (vec)
(with-tramp-connection-property vec "id"
(tramp-message vec 5 "Finding POSIX `id' command")
......
......@@ -1964,7 +1964,7 @@ ARGS are the arguments OPERATION has been called with."
;; Emacs 22+ only.
'set-file-times
;; Emacs 24+ only.
'file-acl 'file-selinux-context
'file-acl 'file-notify-add-watch 'file-selinux-context
'set-file-acl 'set-file-selinux-context
;; XEmacs only.
'abbreviate-file-name 'create-file-buffer
......@@ -2018,6 +2018,10 @@ ARGS are the arguments OPERATION has been called with."
;; XEmacs only.
'dired-print-file 'dired-shell-call-process))
default-directory)
;; PROC.
((eq operation 'file-notify-rm-watch)
(with-current-buffer (process-buffer (nth 0 args))
default-directory))
;; Unknown file primitive.
(t (error "unknown file I/O primitive: %s" operation))))
......
......@@ -4495,20 +4495,6 @@ convenience wrapper around `make-progress-reporter' and friends.
(progress-reporter-done ,temp2)
nil ,@(cdr (cdr spec)))))
;;;; Support for watching filesystem events.
(defun file-notify-handle-event (event)
"Handle file system monitoring event.
If EVENT is a filewatch event, call its callback.
Otherwise, signal a `filewatch-error'."
(interactive "e")
(if (and (eq (car event) 'file-notify)
(>= (length event) 3))
(funcall (nth 2 event) (nth 1 event))
(signal 'filewatch-error
(cons "Not a valid file-notify event" event))))
;;;; Comparing version strings.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment