git.fiddlerwoaroof.com
main.lisp
42dc5c76
 ;; MIT license Edward Langley (c) 2018
 
cc02973e
 (eval-when (:execute :load-toplevel :compile-toplevel)
   (net.didierverna.clon:nickname-package))
42dc5c76
 
e4881c6a
 (defpackage :daydreamer.main
   (:use :cl :fw.lu :alexandria :st :daydreamer.aws-result)
cc02973e
   (:export main dump
            #:stack-parameters
            #:stack-outputs
            #:stack-for-name
5892c84f
            #:watch-stack
            #:stack-info))
42dc5c76
 
e4881c6a
 (in-package :daydreamer.main)
42dc5c76
 
 (define-condition invalid-result (error)
   ())
 
 (defun stack-for-name (name)
   (let* ((aws-result (car (extract-list (cdar (aws/cloudformation:describe-stacks :stack-name name)))))
          (the-stack (extract-stack aws-result)))
     the-stack))
 
9804b881
 (defun print-kvs (prefix formatter stream data)
   (let ((key-key (format nil "~aKey" prefix))
         (value-key (format nil "~aValue" prefix)))
     (mapcar (lambda (inp)
               (let ((k (cadr (assoc key-key inp :test #'equal)))
                     (v (cadr (assoc value-key inp :test #'equal))))
8e5bcff6
                 (format stream formatter k v)))
9804b881
             data)))
42dc5c76
 
 (defun stack-outputs (the-stack)
9804b881
   (print-kvs "Output"
              (tagged-kv-formatter "OUTPUT") t
42dc5c76
              (outputs the-stack)))
 
 (defun stack-parameters (the-stack)
9804b881
   (print-kvs "Parameter"
              (tagged-kv-formatter "PARAMETERS") t
42dc5c76
              (parameters the-stack)))
 
cc02973e
 (defun lt-format (a b &key &allow-other-keys)
   (local-time:format-timestring a b))
42dc5c76
 
cc02973e
 (defgeneric duration-of (timeline)
   (:method ((timeline timeline))
     (local-time-duration:timestamp-difference (end-date-time timeline)
                                               (start-date-time timeline))))
42dc5c76
 
ea8450da
 (defun every-five-seconds (cb args &optional (delay-function #'sleep))
   (loop
dc602477
      for (continue? . next-args) = (multiple-value-list (apply cb args)) then (multiple-value-list (apply cb next-args))
      while continue?
ea8450da
      do (funcall delay-function 5)))
 
 (deftest every-five-seconds ()
   (let ((counter 0)
         delay)
     (flet ((fake-delay (num)
              (incf counter)
              (setf delay num))
            (work ()
              (< counter 10)))
       (every-five-seconds #'work () #'fake-delay)
       (should be = 10 counter)
dc602477
       (should be = 5 delay)))
 
   (let (delay
         (count 0)
         (counters ()))
     (flet ((fake-delay (num)
              (setf delay num))
            (work (counter)
              ;; temporary for initial red...
              (if (> count 10)
                  (throw 'quit nil)
                  (incf count))
 
              (push counter counters)
              (values (< counter 10)
                      (1+ counter))))
       (catch 'quit
         (every-five-seconds #'work '(0) #'fake-delay))
       (should be equal
               (alexandria:iota 11 :start 10 :step -1)
               counters)
ea8450da
       (should be = 5 delay))))
 
dc602477
 (defun parameter-block (the-stack)
   (format t "~& PARAMETERS ~%============~%")
   (stack-parameters the-stack)
   (format t "~&============~2%"))
 
 (defun output-block (the-stack)
   (format t "~2& OUTPUTS ~%=========~%")
   (stack-outputs the-stack)
   (format t "~&=========~%")
   (values))
 
9f1ff408
 (defclass stack-formatter ()
   ((%stack :initarg :stack :accessor stack)
    (%old-status :initarg :old-status :accessor old-status :initform nil)))
 
 (defmethod stack-status ((stack-formatter stack-formatter))
   (when (slot-boundp stack-formatter '%stack)
     (stack-status (stack stack-formatter))))
 
 (defmethod parameters ((stack-formatter stack-formatter))
   (when (slot-boundp stack-formatter '%stack)
     (parameters (stack stack-formatter))))
 
 (defmethod outputs ((stack-formatter stack-formatter))
   (when (slot-boundp stack-formatter '%stack)
     (outputs (stack stack-formatter))))
 
 (defmethod (setf stack) :before (new-value (object stack-formatter))
   (setf (old-status object) (stack-status object)))
 
3c0af7c8
 (defgeneric refresh (stack-formatter)
e4881c6a
   (:method ((stack daydreamer.aws-result:stack))
9f1ff408
     (stack-for-name (stack-name stack))) 
   (:method ((stack-formatter string))
     (make-instance 'stack-formatter :stack (stack-for-name stack-formatter)))
   (:method ((stack-formatter stack-formatter))
3c0af7c8
     (setf (stack stack-formatter) (refresh (stack stack-formatter)))
9f1ff408
     stack-formatter))
 
e4881c6a
 (defmethod old-status ((stack daydreamer.aws-result:stack))
5892c84f
   nil)
 
9f1ff408
 (defun stack-info (the-stack)
   (with-accessors ((old-status old-status)) the-stack
     (let* ((current-status (stack-status the-stack)))
       (unless old-status
         (parameter-block the-stack))
 
       (unless (equal old-status current-status)
         (format t "~&STATUS ~a~%" current-status))
 
       (if (ends-with-subseq "COMPLETE" (symbol-name current-status))
           (output-block the-stack)
           t))))
ea8450da
 
3c0af7c8
 (defmacro refreshing (cb)
   `(lambda (thing)
      (let ((refreshed-thing (refresh thing)))
        (values (,cb refreshed-thing)
                refreshed-thing))))
5892c84f
 
42dc5c76
 (defun watch-stack (name)
d59cfff7
   (format t "~&Watching ~s~2%" name)
3c0af7c8
   (every-five-seconds (refreshing stack-info)
9f1ff408
                       (list name))
d59cfff7
   (fresh-line))
ea8450da