https://github.com/filipesilva/invoker v0.3.6 is out! This is the first public release of Invoker, and feedback/issues/usecases are very welcome.
Invoker is a zero config CLI, HTTP, and REPL interface for Clojure.
Invoked vars run in Clojure if there's a deps.edn, otherwise in Babashka.
Commands will automatically connect to an existing nREPL server if available using .nrepl-port. The nvk httpand nvk repl commands start a nREPL server that can be connected to.
Invoker aims to make the following usecases easy:
• making a simple webapp from scratch, possibly with Datomic
• running functions and inspecting atoms inside an existing process
• running targetted tests with reloaded code
• allowing agents to interact with your clojure process
• adding dependencies and reloading code without restarting the process
I somehow read this, didn't think more about it, then came back and figured how awesome what you've just done is. We can now effectively write shell script that interacts reasonably with one clojure REPL process! Thank you for your foresight. 🙌
One thing — I would love to include this in my projects as a babashka task, eg bb nvk. That would let me track the nvk version in bb.edn, instead of out-of-band bbin.
Thanks again!
heya! yeah it's really meant to support that case, everything (including the add-lib stuff) really runs on the single process if there's one up
hmmm I think you can put what's in the bbin key to run through bb?
{:bbin/bin {nvk {:main-opts ["-m" "invoker.nvk"]}}
:min-bb-version "1.12.208"
:deps {io.github.filipesilva/invoker {:local/root "."}}
:paths ["src" "test" "resources"]}
I don't remember right now what the bb task syntax is for this, but it looks very possible
something like this maybe?
{:tasks
{:requires ([invoker.nvk :as nvk])
nvk (nvk/-main *command-line-args*)}}let me know if it works or if you hit any snag trying to make it work
sorry for the "fire question and disappear"! I tried this, which looks correct to me:
{:deps {io.github.teodorlu/bb-timemachine {:git/tag "v1.0.1" :git/sha "e684c"}
io.github.filipesilva/invoker
{:git/url "",
:git/tag "v0.4.7",
:git/sha "2d77d54869d8694a74fcafabea2536f4868a8387"}}
:tasks
{:requires ([invoker.nvk :as nvk])
nvk (nvk/-main *command-line-args*)}}
but I'm hitting a CLI parsing error:
$ bb nvk
----- Error --------------------------------------------------------------------
Type: java.lang.NullPointerException
Location: /Users/teodorlu/.gitlibs/libs/io.github.filipesilva/invoker/2d77d54869d8694a74fcafabea2536f4868a8387/src/invoker/nvk.clj:219:72
----- Context ------------------------------------------------------------------
215: [k (assoc m :default default)]
216: [k m]))
217:
218: (defn spec-with-defaults [base-spec args]
219: (let [config-path (-> [{:cmds [] :fn identity :spec base-spec}] (cli/dispatch args) :opts :config)
^---
220: _ (when (and (not= config-path "nvk.edn")
221: (not (fs/exists? config-path)))
222: (utils/print-err-exit true 2 (ex-info "Config path does not exist"
223: {:config-path config-path})))
224: dynamic-defaults {:dialect (if (fs/exists? "deps.edn") :clj :bb)
----- Stack trace --------------------------------------------------------------
clojure.string/starts-with? -
babashka.cli/parse-cmds/fn--27323 -
clojure.core/take-while/fn--6007 -
clojure.core/seq--5488 -
babashka.cli/parse-opts -
... (run with --debug to see elided elements)
invoker.nvk/spec-with-defaults - /Users/teodorlu/.gitlibs/libs/io.github.filipesilva/invoker/2d77d54869d8694a74fcafabea2536f4868a8387/src/invoker/nvk.clj:218:1
invoker.nvk/-main - /Users/teodorlu/.gitlibs/libs/io.github.filipesilva/invoker/2d77d54869d8694a74fcafabea2536f4868a8387/src/invoker/nvk.clj:240:20
invoker.nvk/-main - /Users/teodorlu/.gitlibs/libs/io.github.filipesilva/invoker/2d77d54869d8694a74fcafabea2536f4868a8387/src/invoker/nvk.clj:247:9
invoker.nvk/-main - /Users/teodorlu/.gitlibs/libs/io.github.filipesilva/invoker/2d77d54869d8694a74fcafabea2536f4868a8387/src/invoker/nvk.clj:232:1
user-74598898-a28d-49e3-8cb1-bf4074face07 - NO_SOURCE_PATH:38:1 (my motivation for asking was, I can try just call some function in your library from my task, but I would prefer to use what you consider to be the public API!)
wait, I think its (apply f command-line-args), let me check
apply it is!
{:deps {io.github.teodorlu/bb-timemachine {:git/tag "v1.0.1" :git/sha "e684c"}
io.github.filipesilva/invoker
{:git/url "",
:git/tag "v0.4.7",
:git/sha "2d77d54869d8694a74fcafabea2536f4868a8387"}}
:tasks
{:requires ([invoker.nvk :as nvk])
nvk (apply nvk/-main *command-line-args*)}} oh sweet, was gonna get ready to debug it, but it seems no need hahah
I had a similar recipie lying around for https://github.com/teodorlu/bb-timemachine, so it was quick to spot the difference!
the version check seems to be working, which was what I was really worried about... it runs some git commands so I thought maybe they wouldn't work right
so now stuff like bb nvk clojure core inc 1 works?
it does
$ bb nvk clojure core inc 1
2bb-timemachine looks cool, kinda makes me think it should enable function-level dependencies like in the Speculation (I think that was the one) Rich Hickey talk
so it checks stuff out in a temporary dir or in the project dir?
temp dir, uses a worktree
nice
then deletes the dir when the thing completes. We're running branchless at work, and we had a few instances of people pushing partial code! This feels safer to run before pushing.
oh yeah I see how that's really bad on branchless hahah
Just setup invoker at our work codebase. After adding clj-reload hooks to start and stop our system, I saw substantial performance improvements! Cold Kaocha test run in a fresh process: 24 s First invoker test run after the system has been started: 14 s Second invoker test run: 8 s. I copied our bb task installation to an issue, in case you're interested in supporting installation via babashka task: https://github.com/filipesilva/invoker/issues/1
haha yeah I was thinking of adding it to the readme!
I should also add a small primer about it to the nvk readme, or at least about using defonce for atoms, was using nvk today and state atoms with reloads really need it
I just read clj-reload's README proper, and got all I needed from there. But yeah, a note of sorts about assumptions (if you have state, it must play nicely with clj-reload) is probably a good addition.
Just had to mention that seeing the path to invoker's README in the bottom of invoker's helptext gave me yet another spark of joy! Github not needed, I have Emacs. Such a nice little tool. Thanks again. 🙇
I tried to make sure docs were available locally, so it would work well even without internet. The version stuff (used for injecting if needed) also uses the local install if modified, to support hacking on it for your own use cases.