Hash :
79277171
Author :
Date :
2014-10-03T11:42:57
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
;;
;; adams - Remote system administration tools
;;
;; Copyright 2013 Thomas de Grivel <billitch@gmail.com>
;;
;; Permission to use, copy, modify, and distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.
;;
;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
;;
(in-package :adams)
;; Host
(defclass host ()
((name :type string
:initarg :hostname
:reader hostname)
(shell :type shell
:initarg :shell)
(manifest :type manifest
:initarg :manifest
:reader host-manifest)))
(defmethod print-object ((host host) stream)
(print-unreadable-object (host stream :type t :identity t)
(write-string (hostname host) stream)))
;; Host shell
(defgeneric host-connect (host))
(defgeneric host-disconnect (host))
(defgeneric host-shell (host))
(defgeneric (setf host-shell) (shell host))
(defmethod host-shell ((host host))
(if (slot-boundp host 'shell)
(slot-value host 'shell)
(setf (slot-value host 'shell) (host-connect host))))
(defmethod (setf host-shell) ((shell shell) (host host))
(setf (slot-value host 'shell) shell))
(defmethod host-disconnect ((host host))
(when (slot-boundp host 'shell)
(shell-close (host-shell host))
(slot-makunbound host 'shell)))
(defmacro with-connected-host ((var hostname) &body body)
(let ((g!host (gensym "HOST-")))
`(let ((,g!host (make-instance 'ssh-host :hostname ,hostname)))
(unwind-protect (let ((,var ,g!host)) ,@body)
(host-disconnect ,g!host)))))
(defun host-run (host command &rest format-args)
(let ((shell (host-shell host)))
(when (shell-closed-p shell)
(setq shell (host-connect host)))
(apply #'shell-run shell command format-args)))
;; Host manifest
(defmethod slot-unbound (class (host host) (slot-name (eql 'manifest)))
(setf (slot-value host 'manifest) (manifest (hostname host))))
;; localhost
(defvar *localhost* (load-time-value
(make-instance 'host
:hostname "localhost")))
(defmethod host-connect ((host (eql *localhost*)))
(assert (null (host-shell host)))
(setf (host-shell host) (make-shell)))
;; SSH host
(defclass ssh-host (host) ())
(defmethod host-connect ((host ssh-host))
(assert (null (host-shell host)))
(setf (host-shell host) (make-shell "/usr/bin/ssh" (hostname host))))
;; High level API
(defvar *host* *localhost*)
(defmacro with-host (hostname &body body)
`(with-connected-host (*host* ,hostname)
(let ((*manifest* (host-manifest *host*)))
,@body)))
(defun run (command &rest format-args)
(apply #'host-run *host* command format-args))