1 #! /usr/bin/cl-launch -X --
4 (cl:defpackage #:ansible-inventory
6 (:import-from #:cl-launch #:*arguments*))
8 (in-package #:ansible-inventory)
10 ;;;--------------------------------------------------------------------------
11 ;;; General utilities.
13 (defun compose (&rest funcs)
15 (lambda (&rest args) (multiple-value-call g (apply f args))))
16 funcs :initial-value #'values))
18 ;;;--------------------------------------------------------------------------
21 (defvar *print-json-comma*)
23 (defun print-json-itemstart ()
24 (cond (*print-json-comma*
26 (pprint-newline :linear))
28 (setf *print-json-comma* t))))
30 (defun print-json-map* (thunk)
31 (print-json-itemstart)
33 (pprint-indent :block 2)
34 (pprint-newline :linear)
35 (pprint-logical-block (*standard-output* nil)
36 (let ((*print-json-comma* nil)) (funcall thunk)))
38 (pprint-indent :block 0)
39 (pprint-newline :linear)
42 (defmacro print-json-map (&body body)
43 `(print-json-map* (lambda () ,@body)))
45 (defun print-json-list* (thunk)
46 (print-json-itemstart)
48 (pprint-indent :block 2)
49 (pprint-newline :linear)
50 (pprint-logical-block (*standard-output* nil)
51 (let ((*print-json-comma* nil)) (funcall thunk)))
52 (pprint-indent :block 0)
53 (pprint-newline :linear)
56 (defmacro print-json-list (&body body)
57 `(print-json-list* (lambda () ,@body)))
59 (defun print-json-mapping* (label thunk)
60 (print-json-itemstart)
61 (pprint-logical-block (*standard-output* nil)
62 (let ((*print-json-comma* nil))
63 (print-json-simple label))
65 (pprint-newline :miser)
66 (let ((*print-json-comma* nil))
69 (defmacro print-json-mapping (label &body body)
70 `(print-json-mapping* ,label (lambda () ,@body)))
72 (defun print-json-simple (value)
74 (list (print-json-list (dolist (i value) (print-json-simple i))))
75 (hash-table (print-json-map (maphash (lambda (k v)
77 (print-json-simple v)))
80 (print-json-itemstart)
82 (integer (format t "~A" value))
83 (float (format t "~G" value))
84 (rational (format t "~G" (float value 0.0d0)))
85 (string (format t "~S" value))
86 ((eql t) (princ "true"))
87 ((eql nil) (princ "false"))
88 ((eql :undefined) (princ "undefined"))
89 (symbol (format t "~S" (string-downcase value)))))))
91 (defun print-json* (thunk)
92 (let ((*print-json-comma* nil))
93 (pprint-logical-block (*standard-output* nil)
97 (defmacro print-json (&body body)
98 `(print-json* (lambda () ,@body)))
100 ;;;--------------------------------------------------------------------------
101 ;;; Host definitions.
103 (defvar *hosts* (make-hash-table))
106 (defun addhost (name alist)
107 (setf (gethash name *hosts*) alist))
110 (defmacro defhost (name &body alist)
111 `(progn (addhost ',name ',alist) ',name))
114 (defun host-plist (name)
115 (multiple-value-bind (plist foundp) (gethash name *hosts*)
116 (unless foundp (error "Host ~S not found" name))
120 (defun hostprop (name prop &optional default)
121 (multiple-value-bind (found-name value tail)
122 (get-properties (host-plist name) (list prop))
123 (declare (ignore found-name))
126 (values default nil))))
127 (defun (setf hostprop) (value name prop &optional default)
128 (declare (ignore default))
129 (let ((plist (host-plist name)))
130 (multiple-value-bind (found-name found-value tail)
131 (get-properties plist (list prop))
132 (declare (ignore found-name found-value))
134 (setf (cadr tail) value)
135 (setf (gethash name *hosts*)
136 (cons prop (cons value plist))))
139 (export 'hostprop-default)
140 (defun hostprop-default (host prop value)
141 (multiple-value-bind (found-value foundp) (hostprop host prop)
142 (declare (ignore found-value))
143 (unless foundp (setf (hostprop host prop) value))))
146 (defun hostpropp (host prop)
147 (multiple-value-bind (value foundp) (hostprop host prop)
148 (declare (ignore value))
152 (defun maphosts (func)
153 (maphash (lambda (name plist)
154 (declare (ignore plist))
159 (defmacro dohosts ((hostvar &optional valueform) &body body)
160 `(block nil (maphosts (lambda (,hostvar) ,@body)) ,valueform))
162 ;;;--------------------------------------------------------------------------
163 ;;; Group definitions.
165 (defvar *groups* nil)
168 (defun add-group (name type func)
169 (let* ((found (assoc name *groups*))
174 (when (funcall func host) (push host list)))))
178 (setf (cdr found) list)
179 (push (cons name list) *groups*))))
182 (defmacro defgroup (name type args &body body)
183 `(progn (add-group ',name ,type
186 (destructuring-bind (hostvar) args
187 `(lambda (,hostvar) ,@body)))
189 (destructuring-bind () args
190 `(lambda () ,@body)))))
193 ;;;--------------------------------------------------------------------------
194 ;;; Post-processing hooks.
196 (defstruct hook-entry
200 (export '(prio-props prio-groups))
201 (defconstant prio-props 10)
202 (defconstant prio-groups 20)
204 (defvar *hostproc-hooks* nil)
207 (defun addhook (prio func)
208 (push (make-hook-entry :prio prio :func func) *hostproc-hooks*))
211 (defmacro defhook ((prio) &body body)
212 `(addhook ,prio (lambda () ,@body)))
214 ;;;--------------------------------------------------------------------------
215 ;;; Read the input file and hook definitions.
218 #.(or *compile-file-pathname* *load-pathname*))
220 (let ((pkg (make-package "ANSIBLE-INVENTORY-USER"
221 :use '("CL" "ANSIBLE-INVENTORY")))
223 (loop (let* ((arg (pop args))
225 (cond ((string= arg "--") (return))
226 ((string= arg "-") (push arg args) (return))
227 ((and (plusp (length arg))
228 (char= (char arg 0) #\-))
232 (cond ((< (1+ i) len)
233 (prog1 (subseq arg (1+ i))
238 (error "missing argument"))))))
240 (#\h (format t "usage: ~A FILE ...~%"
241 (pathname-name *progname*)))
242 (t (error "unknown option `-~A'" (char arg i))))))
243 (t (push arg args) (return)))))
244 (format t ";; remaining args = ~S~%" args)
246 (let ((*package* pkg))
247 (load arg :verbose nil))))
249 ;;;--------------------------------------------------------------------------
252 (setf *hostproc-hooks* (sort *hostproc-hooks* #'< :key #'hook-entry-prio))
253 (mapc (compose #'hook-entry-func #'funcall) *hostproc-hooks*)
255 ;;;--------------------------------------------------------------------------
256 ;;; Output the definitions.
258 (setf *print-right-margin* 77)
261 (print-json-mapping "all"
262 (print-json-list (maphosts #'print-json-simple)))
263 (dolist (assoc *groups*)
264 (print-json-mapping (car assoc)
266 (mapc #'print-json-simple (cdr assoc)))))
267 (print-json-mapping "_meta"
269 (print-json-mapping "hostvars"
271 (maphash (lambda (host plist)
272 (print-json-mapping host
274 (do ((plist plist (cddr plist)))
276 (print-json-mapping (car plist)
277 (print-json-simple (cadr plist)))))))
280 ;;;----- That's all, folks --------------------------------------------------