Home

Awesome

Background

This is a babashka pod that binds some golang functions into a clojure namespace. Using this pod, clojure programs can parse dockerfiles and docker images names using the "official" docker golang libraries.

Usage

(require '[babashka.pods :as pods])
(pods/load-pod 'atomisthq/tools.docker "0.1.0")
; OR use a locally built pod binary
#_(pods/load-pod "./pod-atomisthq-tools.docker")

;; load-pod will create this namespace with two vars
(require '[pod.atomisthq.docker :as docker])

;; parse image names using github.com/docker/distribution
;; turns golang structs into clojure maps
(docker/parse-image-name "gcr.io/whatever:tag")
;; automatically turns golang errors into Exceptions
(try
  (docker/parse-image-name "gcr.io/whatever/:tag")
  (catch Exception e
    ;; invalid reference format
    (println (.getMessage e))))

;; parse dockerfiles using github.com/moby/buildkit
;; returns the Result struct transformed to a clojure map
(docker/parse-dockerfile "FROM \\\n    gcr.io/whatever:tag\nCMD [\"run\"]")

Loading 'atomisthq/docker from the pod registry will download the binary into ${user.home}/.babashka/pods/registry (the $BABASHKA_PODS_DIR environment variable will be used if it exists).

Building

To build the golang parser binary locally, run go build.

go build -o pod-babashka-docker

Create vonwig/pod-atomisthq-tools.docker which is a manifest list with pod binaries for both amd64 and arm64. This image is a good way to pull the pod binaries into skill containers.

bb build-pod-image

Releasing

Creating a release from a tag will trigger a build and release

Namespace generation

The pods/load-pod call is convenient for a repl-session, or a script, but what if you are aot compiling, or building a native binary. In the example above, the namespaces emitted by pods/load-pod are not available until runtime.

Here is an example of bindings that will resolve at compile-time and go through the same dispatch.

; require the babashka.pods in a namespace
(require '[babashka.pods.impl :as impl])

; call at runtime to initialize pod system
(defn load-pod
  ([pod-spec] (load-pod pod-spec nil))
  ([pod-spec version opts] (load-pod pod-spec (assoc opts :version version)))
  ([pod-spec opts]
   (let [opts (if (string? opts)
                {:version opts}
                opts)
         pod (impl/load-pod
              pod-spec
              (merge {:remove-ns remove-ns
                      :resolve (fn [sym]
                                 (or (resolve sym)
                                     (intern
                                      (create-ns (symbol (namespace sym)))
                                      (symbol (name sym)))))}
                     opts))]
     (future (impl/processor pod))
     {:pod/id (:pod-id pod)})))

;; statically define dispatch functions - this is synchronous
(defn parse [s]
  (impl/invoke-public "pod.atomisthq.docker" "pod.atomisthq.docker/parse-dockerfile" [s] {}))

;; async example
(defn generate-sbom [s]
  (impl/invoke-public "pod.atomisthq.docker" "pod.atomisthq.docker/-generate-sbom"
    [s cb]
    {:handlers {:done (fn [])
                :success cb
                :error (fn [err]}})))
(pods/load-pod 'atomisthq/tools.docker "7.3.0")
(pods/load-pod "my-executable")

This method of dispatch does not require any dynamic namespace generation.

Contributing

You can find information about contributing to this project in the CONTRIBUTING.md