From: meissner@osf.ORG
Subject: Updating another host when you save files
Organization: Source only  Discussion and requests in gnu.emacs.help.
Distribution: gnu
Date: Tue, 6 Oct 1992 09:47:51 GMT

Somebody asked recently how to update files automatically on another
host when doing saves.  I have two main systems ('curley', a
DECstation running OSF/1 and 'tiktok', a 386 running OSF/1) and I
recently got burned by editing a file on curley, and trying to use it
on tiktok before my nightly rdist kept everything up to date.  So I
wrote the following code.  Rather than doing the rcp everytime you do
a save, it puts it in the buffer *update*, and whenever the elisp
function do-update-command is executed.  I then added code in my
function bound to ^X^C which calls do-update-command (and of course
you can call it interactively as well).  I find this less obtrusive
then answering y/n every time I save the file.  Obviously, you will
have to customize it for your system.

The code also will update the X resources if either the .Xresources or
.Xdefaults files is modified; rebuild mail aliases if the .mailrc is
modified; and byte-compile elisp files which have already been
byte-compiled.

;; Meissner code to do stuff after saving a file.
;; Copyright (C) 1992, Michael Meissner		(meissner@osf.org)

;; This file is not a part of GNU Emacs.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY.  No author or distributor
;; accepts responsibility to anyone for the consequences of using it
;; or for whether it serves any particular purpose or works at all,
;; unless he says so in writing.  Refer to the GNU Emacs General Public
;; License for full details.

;; Everyone is granted permission to copy, modify and redistribute
;; GNU Emacs, but only under the conditions described in the
;; GNU Emacs General Public License.   A copy of this license is
;; supposed to have been given to you along with GNU Emacs so you
;; can know your rights and responsibilities.  It should be in a
;; file named COPYING.  Among other things, the copyright notice
;; and this notice must be preserved on all copies.


(defvar mrm-recursive-write-files nil "True when we are executing inside basic-save-buffer.")

(defvar curley-p (string-match "^curley" (system-name)) "True if running on curley.osf.org.")
(defvar tiktok-p (string-match "^tiktok" (system-name)) "True if running on tiktok.osf.org.")

;; Save FSF version of basic-save-buffer
(if (not (fboundp 'fsf-basic-save-buffer))
    (fset 'fsf-basic-save-buffer (symbol-function 'basic-save-buffer)))

(defun add-update-command (cmd)
  "Add cmd to the *update* buffer, unless it already exists."
  (interactive "sCommand to add? ")
  (let ((buf (get-buffer-create "*update*")))
    (save-window-excursion
      (set-buffer buf)
      (goto-char (point-min))
      (if (not (re-search-forward (concat "^" (regexp-quote cmd) "$") nil t))
	  (progn
	    (goto-char (point-max))
	    (insert cmd "\n")
	    (message (concat "do M-x do-update-command to do: " cmd))))))
  cmd)

(defun do-update-command ()
  "If the *update* buffer exists, execute it's contents as a shell command."
  (interactive)
  (let ((buf (get-buffer "*update*")) (cmd))
    (if buf
	(progn
	  (save-window-excursion
	    (set-buffer buf)
	    (setq cmd (buffer-string)))
	  (kill-buffer buf)))
    (if cmd
	(shell-command cmd))))

(defun basic-save-buffer ()
  "Save the current buffer in its visited file, if it has been modified.
Then do the following.:

   1.	Possibly do xrdb -load .Xdefaults if it was modified;
   2.	Cause the mail aliases to be rebuilt if .mailrc is stored;
   3.	Byte compile a lisp file when it is stored;
   4.	Update tiktok and/or curley when a common file is updated."

  (let ((modified (buffer-modified-p))
	(dir)
	(other-host (if tiktok-p "curley" "tiktok"))
	(last-arg)
	(command)
	(possible-elc-file (if (string-match ".el$" buffer-file-name)
			       (concat buffer-file-name "c")
			     nil)))

    (fsf-basic-save-buffer)

    (if (and (not mrm-recursive-write-files) modified buffer-file-name (file-exists-p buffer-file-name))
	(unwind-protect
	    (progn
	      (setq mrm-recursive-write-files t)

	      ;; Is this the X resource file?
	      (if (and (eq window-system 'x)
		       (eq window-system-version 11)
		       (string-match (concat (expand-file-name "~") "/.X\\(defaults\\|resources\\)$") buffer-file-name)
		       (y-or-n-p "Rebuild X resources? "))
		  (shell-command (concat "xrdb -load " buffer-file-name)))

	      ;; Need to rebuild mail aliases?
	      (if (string-equal buffer-file-name (expand-file-name "~/.mailrc"))
		  (progn
		    (setq mail-aliases t)
		    (message "Mail will be rebuilt the next time mail is sent.")))

	      ;; Is this a lisp file we need to byte-compile?
	      (if (and possible-elc-file (not (file-exists-p possible-elc-file)))
		  (setq possible-elc-file nil))

	      (if possible-elc-file
		  (byte-compile-file buffer-file-name))

	      ;; Do we need to update the other host?
	      (if (and (or curley-p tiktok-p)
		       (string-match (concat "^"
					     (expand-file-name "~")
					     "\\(\\|/elisp\\|/bin\\.sh\\|/bin\\.perl\\|News\\)/[^/]+$")
				     buffer-file-name)
		       (setq dir (substring buffer-file-name (match-beginning 1) (match-end 1)))
		       (not (string-equal buffer-file-name (expand-file-name "~/INBOX")))
		       (not (string-match "[%#%]$" buffer-file-name)))

		  (progn
		    (setq command (concat "/usr/bin/rcp " buffer-file-name))
		    (setq last-arg (concat other-host ":~" dir))
		    (if possible-elc-file
			(setq command (concat command " " possible-elc-file)))

		    (add-update-command (concat command " " last-arg)))))

	  ;; unwind-protect unwindforms
	  (setq mrm-recursive-write-files nil)))))


(defun mrm-save-buffers-kill-emacs (query)
  "Meissner's extended kill-emacs to kill news safely before saving
buffers, and do any pending updates to tiktok/curley."

  (interactive "P")

  (if (and (boundp 'nntp-server-process) nntp-server-process)
      (gnus-Group-exit))

  (save-some-buffers query)

  (let ((proc-list (process-list)) proc status name)
    (while proc-list
      (progn
	(setq proc (car proc-list))
	(setq proc-list (cdr proc-list))
	(setq status (process-status proc))
	(setq name (process-name proc))
	(if (and (or (eq status 'run) (eq status 'stop))
	     	 (not (string-equal name "server"))
		 (y-or-n-p (concat "Kill process " name "? ")))
	    (delete-process name)))))

  (let ((buf (get-buffer "*update*")))
    (if (and buf
	     (buffer-modified-p buf)
	     (or query
		 (y-or-n-p "Execute update commands? ")))
	(do-update-command)))

  (if (or query
	  (not (boundp 'epoch::version)
	  (y-or-n-p "Exit Emacs? "))
      (kill-emacs (or query (boundp 'epoch::version))))))

(global-set-key "\C-x\C-c" 'mrm-save-buffers-kill-emacs)

--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142

You are in a twisty little passage of standards, all conflicting.