Support declarative pods loaded on require

This commit is contained in:
Wes Morgan 2022-03-18 15:49:46 -06:00
parent 8d1d19d331
commit f707705cf4
No known key found for this signature in database
GPG key ID: 5639E4CBFA17DC84
3 changed files with 127 additions and 50 deletions

View file

@ -248,15 +248,18 @@
(defn lookup-pod [pod-id] (defn lookup-pod [pod-id]
(get @pods pod-id)) (get @pods pod-id))
(defn destroy* [{:keys [:stdin :process :ops]}]
(if (contains? ops :shutdown)
(do (write stdin
{"op" "shutdown"
"id" (next-id)})
(.waitFor ^Process process))
(.destroy ^Process process)))
(defn destroy [pod-id-or-pod] (defn destroy [pod-id-or-pod]
(let [pod-id (get-pod-id pod-id-or-pod)] (let [pod-id (get-pod-id pod-id-or-pod)]
(when-let [pod (lookup-pod pod-id)] (when-let [pod (lookup-pod pod-id)]
(if (contains? (:ops pod) :shutdown) (destroy* pod)
(do (write (:stdin pod)
{"op" "shutdown"
"id" (next-id)})
(.waitFor ^Process (:process pod)))
(.destroy ^Process (:process pod)))
(when-let [rns (:remove-ns pod)] (when-let [rns (:remove-ns pod)]
(doseq [[ns-name _] (:namespaces pod)] (doseq [[ns-name _] (:namespaces pod)]
(rns ns-name)))) (rns ns-name))))
@ -311,22 +314,22 @@
(binding [*out* *err*] (binding [*out* *err*]
(println (str/join " " (map pr-str strs))))) (println (str/join " " (map pr-str strs)))))
(defn load-pod (defn resolve-pod [pod-spec {:keys [:version :force] :as opts}]
([pod-spec] (load-pod pod-spec nil)) (let [resolved (when (qualified-symbol? pod-spec)
([pod-spec opts]
(let [{:keys [:version :force]} opts
resolved (when (qualified-symbol? pod-spec)
(resolver/resolve pod-spec version force)) (resolver/resolve pod-spec version force))
opts (if resolved opts (if resolved
(if-let [extra-opts (:options resolved)] (if-let [extra-opts (:options resolved)]
(merge opts extra-opts) (merge opts extra-opts)
opts) opts)
opts) opts)
{:keys [:remove-ns :resolve :transport]} opts pod-spec (cond
pod-spec (cond resolved [(:executable resolved)] resolved [(:executable resolved)]
(string? pod-spec) [pod-spec] (string? pod-spec) [pod-spec]
:else pod-spec) :else pod-spec)]
pb (ProcessBuilder. ^java.util.List pod-spec) {:pod-spec pod-spec, :opts opts}))
(defn run-pod [pod-spec {:keys [:transport] :as _opts}]
(let [pb (ProcessBuilder. ^java.util.List pod-spec)
socket? (identical? :socket transport) socket? (identical? :socket transport)
_ (if socket? _ (if socket?
(.inheritIO pb) (.inheritIO pb)
@ -349,14 +352,48 @@
[socket [socket
(.getOutputStream socket) (.getOutputStream socket)
(PushbackInputStream. (.getInputStream socket))]) (PushbackInputStream. (.getInputStream socket))])
[nil (.getOutputStream p) (java.io.PushbackInputStream. (.getInputStream p))]) [nil (.getOutputStream p) (java.io.PushbackInputStream. (.getInputStream p))])]
_ (write stdin {"op" "describe" {:process p
:socket socket
:stdin stdin
:stdout stdout}))
(defn describe-pod [{:keys [:stdin :stdout]}]
(write stdin {"op" "describe"
"id" (next-id)}) "id" (next-id)})
reply (read stdout) (read stdout))
format (-> (get reply "format") bytes->string keyword)
ops (some->> (get reply "ops") keys (map keyword) set) (defn describe->ops [describe-reply]
(some->> (get describe-reply "ops") keys (map keyword) set))
(defn describe->metadata [describe-reply]
(let [format (-> (get describe-reply "format") bytes->string keyword)
ops (describe->ops describe-reply)
readers (when (identical? :edn format) readers (when (identical? :edn format)
(read-readers reply resolve)) (read-readers describe-reply resolve))]
{:format format, :ops ops, :readers readers}))
(defn load-pod-metadata [pod-spec opts]
(let [{:keys [:pod-spec :opts]} (resolve-pod pod-spec opts)
running-pod (run-pod pod-spec opts)
describe-reply (describe-pod running-pod)
ops (describe->ops describe-reply)]
(future (destroy* (assoc running-pod :ops ops)))
describe-reply))
(defn load-pod
([pod-spec] (load-pod pod-spec nil))
([pod-spec opts]
(let [{:keys [:pod-spec :opts]} (resolve-pod pod-spec opts)
{:keys [:remove-ns :resolve]} opts
{p :process, stdin :stdin, stdout :stdout, socket :socket
:as running-pod}
(run-pod pod-spec opts)
reply (or (:metadata opts)
(describe-pod running-pod))
{:keys [:format :ops :readers]} (describe->metadata reply)
pod {:process p pod {:process p
:pod-spec pod-spec :pod-spec pod-spec
:stdin stdin :stdin stdin

View file

@ -18,6 +18,7 @@
(def os {:os/name (System/getProperty "os.name") (def os {:os/name (System/getProperty "os.name")
:os/arch (let [arch (System/getProperty "os.arch")] :os/arch (let [arch (System/getProperty "os.arch")]
(normalize-arch arch))}) (normalize-arch arch))})
(defn warn [& strs] (defn warn [& strs]
(binding [*out* *err*] (binding [*out* *err*]
(apply println strs))) (apply println strs)))

View file

@ -1,6 +1,11 @@
(ns babashka.pods.sci (ns babashka.pods.sci
(:require [babashka.pods.impl :as impl] (:require [babashka.pods.impl :as impl]
[sci.core :as sci])) [sci.core :as sci]
[clojure.java.io :as io]
[babashka.pods.impl.resolver :as resolver]
[clojure.edn :as edn]
[clojure.walk :as walk])
(:import (java.io DataInputStream PushbackInputStream)))
(defn- process-namespace [ctx {:keys [:name :vars]}] (defn- process-namespace [ctx {:keys [:name :vars]}]
(let [env (:env ctx) (let [env (:env ctx)
@ -19,6 +24,40 @@
(string? var-value) (string? var-value)
(sci/eval-string* ctx var-value)))))) (sci/eval-string* ctx var-value))))))
(defn metadata-cache-file [pod-spec {:keys [:version]}]
(io/file (resolver/cache-dir {:pod/name pod-spec :pod/version version})
"metadata.cache"))
(defn load-metadata-from-cache [pod-spec opts]
(let [cache-file (metadata-cache-file pod-spec opts)]
(when (.exists cache-file)
(with-open [r (PushbackInputStream. (io/input-stream cache-file))]
(impl/read r)))))
(defn load-pod-metadata* [pod-spec {:keys [:version] :as opts}]
(let [metadata (impl/load-pod-metadata pod-spec opts)
cache-file (when (qualified-symbol? pod-spec) ; don't cache local pods b/c their namespaces can change
(metadata-cache-file pod-spec opts))]
(when cache-file
(with-open [w (io/output-stream cache-file)]
(impl/write w metadata)))
metadata))
(defn load-pod-metadata [ctx pod-spec {:keys [:version] :as opts}]
(let [metadata
(if-let [cached-metadata (when (qualified-symbol? pod-spec) ; don't cache local pods b/c their namespaces can change
(load-metadata-from-cache pod-spec opts))]
cached-metadata
(load-pod-metadata* pod-spec opts))]
(dorun
(for [ns (get metadata "namespaces")]
(let [ns-sym (-> ns (get "name") impl/bytes->string symbol)
key-path [:pod-namespaces ns-sym]
env (:env ctx)]
(swap! env assoc-in key-path
{:pod-spec pod-spec
:opts (assoc opts :metadata metadata)}))))))
(defn load-pod (defn load-pod
([ctx pod-spec] (load-pod ctx pod-spec nil)) ([ctx pod-spec] (load-pod ctx pod-spec nil))
([ctx pod-spec version opts] (load-pod ctx pod-spec (assoc opts :version version))) ([ctx pod-spec version opts] (load-pod ctx pod-spec (assoc opts :version version)))