watch-outputs.fnl (3384B)
1 (local { : %% : system : assoc : split : table= : dig } (require :anoia)) 2 (local svc (require :anoia.svc)) 3 (local { : kill &as ll} (require :lualinux)) 4 (import-macros { : define-tests : expect : expect= } :anoia.assert) 5 6 (local { : view } (require :fennel)) 7 8 (fn output-refs [outputs] 9 (let [result {}] 10 (each [_ v (ipairs outputs)] 11 (let [[service path] (split ":" v) 12 paths (or (. result service) [])] 13 (table.insert paths (split "/" path )) 14 (tset result service paths))) 15 result)) 16 17 (fn parse-args [args] 18 (match args 19 ["-r" service & rest] (assoc (parse-args rest) 20 :controlled-service service 21 :action :restart) 22 ["-R" service & rest] (assoc (parse-args rest) 23 :controlled-service service 24 :action :restart-all) 25 ["-s" signal service & rest] (assoc (parse-args rest) 26 :controlled-service service 27 :action [:signal signal]) 28 outputs { :output-references (output-refs outputs) } )) 29 30 (define-tests 31 (expect= (parse-args ["-r" "daemon" 32 "/nix/store/s1:out1" 33 "/nix/store/s2:out1" "/nix/store/s2:out2/ifname"]) 34 {:action "restart" 35 :controlled-service "daemon" 36 :output-references 37 {"/nix/store/s1" [["out1"]] 38 "/nix/store/s2" [["out1"] ["out2" "ifname"]]}} 39 )) 40 41 (fn changed? [paths old-tree new-tree] 42 (accumulate [changed? false 43 _ path (ipairs paths)] 44 (or changed? (not (table= (dig old-tree path) (dig new-tree path)))))) 45 46 (define-tests 47 (expect (changed? [["ifname"]] {:ifname "true"} {:ifindex 2})) 48 (expect (changed? [["ifname"]] {:ifname "true"} {:ifname "false"})) 49 (expect (not (changed? [["ifname"]] {:ifname "true"} {:ifname "true"}))) 50 (expect (not (changed? [["mtu"]] {:ifname "true"} {:ifname "false"}))) 51 (expect (not (changed? [["mtu"]] {:ifname "true"} {:ifname "false"}))) 52 ) 53 54 (fn do-action [action service] 55 (case action 56 :restart (system (%% "s6-svc -r /run/service/%s" service)) 57 :restart-all (system (%% "s6-rc -b -d change %q; s6-rc-up-tree %q" service service)) 58 [:signal n] (system (%% "s6-svc -s %q /run/service/%s" n service)))) 59 60 (local POLLIN 0x0001) 61 (local POLLHUP 0x0010) 62 63 (fn wait-for-change [services] 64 (let [pollfds (collect [s _p (ipairs services)] 65 (bor (lshift (s:fileno) 32) 66 (lshift (bor POLLIN POLLHUP) 16)))] 67 (ll.poll pollfds))) 68 69 (fn open-services [output-references] 70 (collect [s p (pairs output-references)] 71 (values (svc.open s) p))) 72 73 (fn run [] 74 (let [trees {} 75 { 76 : output-references 77 : controlled-service 78 : action 79 : watched-service 80 : paths } (parse-args arg) 81 services (open-services output-references)] 82 (while true 83 (when 84 (accumulate [changed false 85 service paths (pairs services)] 86 (let [new-tree (service:output ".")] 87 (if (changed? paths (or (. trees service) {}) new-tree) 88 (do (tset trees service new-tree) true) 89 changed))) 90 (do-action action controlled-service)) 91 (wait-for-change services)))) 92 93 94 95 96 { : run }