5.1 KiB
5.1 KiB
Pods distributed as manifest libraries
Babashka library pods are a way of distributing pods that uses the normal Clojure library dependency system to install and load pods. It eliminates the need for the centralized babashka pod registry because the pod manifest is (the only thing) downloaded in the library JAR file. This document assumes you are already familiar with Babashka pods themselves and only covers distributing them via Clojure libraries.
Let's break down the various components of how this works:
- The
pod-manifest.ednfile- The first thing your pod needs is a
pod-manifest.ednfile. It is recommended to store this in your pod project'sresourcesdir under a directory hierarchy matching your pod's top-level exposed namespace (but replacing hyphens with underscores as usual in Clojure → Java name munging). So, for example, if your pod exposes namespaces starting withpod.foo, you should put yourpod-manifest.ednin this path in your pod project:resources/pod/foo/pod-manifest.edn.- By putting your
pod-manifest.ednfile in this namespace-mirroring directory hierarchy inside yourresourcesdir, you can consume it while developing your pod using tools.deps' handy:local/rootfeature. - If you have more than one pod in the same project (or just prefer
it), you can nest the
pod-manifest.ednfiles deeper into their respective namespace hierarchies. As long as there are at least two namespace element directories, babashka will find the correspondingpod-manifest.ednat runtime. So, for example, you can havefoo.bar.baz.qux→resources/foo/bar/baz/qux/pod-manifest.ednbut not justfoo→resources/foo/pod-manifest.edn. This is because a) single-element namespaces are frowned upon anyway in Clojure and b) the first namespace element is often justcomorpodor similar andpod/pod-manifest.ednwould be a very ambiguous resource path to look for in a typical classpath.
- By putting your
- Make sure the
resourcesdir is in the:pathsvector in your pod project'sdeps.ednfile. E.g.:paths ["src" "resources"]. - The format of the
pod-manifest.ednfile looks like this:
- The first thing your pod needs is a
{:pod/name pod.foo/bar
:pod/description "Foo bar pod"
:pod/version "0.4.0"
:pod/license "MIT"
:pod/artifacts
[{:os/name "Linux.*"
:os/arch "amd64"
:artifact/url "https://github.com/foo/pod-bar/releases/download/v0.4.0/pod-foo-bar-linux-amd64.zip"
:artifact/executable "pod-foo-bar"}
{:os/name "Linux.*"
:os/arch "aarch64"
:artifact/url "https://github.com/foo/pod-bar/releases/download/v0.4.0/pod-foo-bar-linux-arm64.zip"
:artifact/executable "pod-foo-bar"}
{:os/name "Mac.*"
:os/arch "amd64"
:artifact/url "https://github.com/foo/pod-bar/releases/download/v0.4.0/pod-foo-bar-macos-amd64.zip"
:artifact/executable "pod-foo-bar"}]}
- The library JAR file
- This JAR file can be built however you want (but see below for an example
tools.build
build.cljsnippet for generating it), but it must contain apod-manifest.ednfile in a path corresponding to your pod's top-level namespace as described above. For example, if your pod exposes the namespacespod.foo.bar.baz&pod.foo.bar.quxthen you should have this directory layout inside your JAR file:pod/foo/bar/pod-manifest.edn. - You then distribute this library JAR to any Maven repo you like (e.g. Clojars).
- This JAR file can be built however you want (but see below for an example
tools.build
- The consuming project
- In the project that wants to use your
pod.foo/barpod, you add the library's Maven coordinates to yourdeps.ednorbb.edn:depssection. This will put thepod/foo/bar/pod-manifest.ednfile onto your project's classpath.bbwill then be able to find your pod's manifest and install and load the pod.
- In the project that wants to use your
- Example
build.cljsnippet for building the library JAR
(ns build
(:require
[clojure.string :as str]
[clojure.tools.build.api :as b]))
(def lib 'pod.foo/bar)
(def version "0.4.0")
(def jar-sources "resources")
(def class-dir "target/resources")
(def basis (b/create-basis {:project "deps.edn"}))
(def pod-manifest "pod/foo/bar/pod-manifest.edn")
(def jar-file (format "target/%s-%s.jar" (-> lib namespace (str/replace "." "-")) (name lib)))
(defn clean [_]
(b/delete {:path "target"}))
(defn jar [_]
(b/write-pom {:class-dir class-dir
:lib lib
:version version
:basis basis})
(b/copy-file {:src (str jar-sources "/" pod-manifest)
:target (str class-dir "/" pod-manifest)})
(b/jar {:class-dir class-dir
:jar-file jar-file}))
;; optional - allows you to install the JAR to your local ~/.m2/repository for testing
(defn install [_]
(jar nil)
(b/install {:basis basis
:lib lib
:version version
:jar-file jar-file
:class-dir class-dir}))
You can then build this pod library via: clj -T:build jar and the JAR file will be in target/pod-foo-bar.jar.