This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-03-28
Channels
- # announcements (34)
- # babashka (46)
- # beginners (187)
- # biff (2)
- # calva (5)
- # cider (10)
- # clj-http (2)
- # clj-kondo (14)
- # cljs-dev (31)
- # clojars (3)
- # clojure (43)
- # clojure-europe (25)
- # clojure-nl (1)
- # clojure-uk (3)
- # clojurescript (4)
- # clr (1)
- # cursive (1)
- # datalevin (50)
- # datomic (1)
- # emacs (12)
- # etaoin (6)
- # fulcro (7)
- # helix (21)
- # hyperfiddle (20)
- # kaocha (5)
- # lsp (14)
- # malli (10)
- # off-topic (58)
- # polylith (7)
- # portal (5)
- # reagent (39)
- # reitit (10)
- # releases (11)
- # reveal (14)
- # scittle (7)
- # shadow-cljs (58)
- # sql (8)
- # tools-deps (7)
I have been playing with babashka CLI, and found 2 bits worth mention: First Q: is there a pure flag (implicit boolean/true) option? I haven’t found it yet:
(def concat-files
[{:cmds ["concat"]
:coerce {:files []}
:args->opts (repeat :files)
:fn println}])
(cli/dispatch concat-files ["concat" "f1" "f2"])
(cli/dispatch concat-files ["concat" "--opt1" "arg1" "file1" "file2"])
; WANT: flag1 -> implicit boolean, eg --dry-run, but flag1 consumes file1,
; GET: :opts {:flag1 f1, :files [f2]}
(cli/dispatch concat-files ["concat" "--flag1" "file1" "file2"])
I tried reading the parse logic, and got lost as a non-native learning clj speaker 🙂 https://github.com/babashka/cli/blob/main/src/babashka/cli.cljc#L361 suggests that it might be possible, and I thought I’d ask here for a quick check.
Second Observation: I haven’t found a way to do sth like -X foo1 -X foo2 file1 file2
. I tried coercing both X
and args->opts
with a coerce on files, but X consumes the whole array. Explicitly using --
in between works, but is not ideal.
(println
(cli/parse-args
["-X" "foo1" "-X" "foo2" "file1" "file2"]
{:coerce {:X [] :files []}
:args->opts (repeat :files)}))
; {:opts {:X [foo1 foo2 file1 file2]}}
(println
(cli/parse-args
["-X" "foo1" "-X" "foo2" "--" "file1" "file2"]
{:coerce {:X [] :files []}
:args->opts (repeat :files)}))
; {:args [file1 file2], :opts {:X [foo1 foo2]}}
@U3LHMD2E8 First: yes, use {:coerce {:opt :boolean}}
for flags
user=> (cli/parse-opts ["-X" "file1.clj" "-X" "file2.clj"] {:coerce {:X [:string]}})
{:X ["file1.clj" "file2.clj"]}
All together:
user=> (cli/parse-args ["-X" "file1.clj" "-X" "file2.clj" "--myflag" "arg1"] {:coerce {:myflag :boolean :X [:string]}})
{:args ["arg1"], :opts {:X ["file1.clj" "file2.clj"], :myflag true}}
> {:coerce {:X [:string]}}
The additional :string
doesn’t seem to change behavior:
(def args ["-X" "foo1" "-X" "foo2" "file1" "file2"])
(cli/parse-args args ; original
{:coerce {:X [] :files []}
:args->opts (repeat :files)})
(cli/parse-args args ; explicit :string
{:coerce {:X [:string] :files []}
:args->opts (repeat :files)})
(cli/parse-args args ; explicit :string in both
{:coerce {:X [:string] :files [:string]}
:args->opts (repeat :files)})
...
user=> {:opts {:X ["foo1" "foo2" "file1" "file2"]}}
user=> {:opts {:X ["foo1" "foo2" "file1" "file2"]}}
user=> {:opts {:X ["foo1" "foo2" "file1" "file2"]}}
babashka cli supports two ways of specifying multiple values: either by repeating the option name + value or by providing the option name followed by multiple values
user=> (def args ["-X" "foo1" "-X" "foo2" "--" "file1" "file2"])
#'user/args
user=> (cli/parse-args args {:coerce {:X [] :files []} :args->opts (repeat :files)})
{:args ["file1" "file2"], :opts {:X ["foo1" "foo2"]}}
Ok, makes sense then: this particular form (with the args->opts coersion) will only with with --
in the presence of a trailing array-stuffing opt.
For this it’s only a personal tool — I brought up these since they’re common CLI patterns, and in my experience a single --arg
rarely takes >1 value
if it doesn't take > 1 value you should not specify it as something that can be multiple with :coerce []
user=> (cli/parse-args ["--foo" "1" "a" "b" "c"])
{:args ["a" "b" "c"], :opts {:foo 1}}
user=> (cli/parse-args ["--foo" "1" "a" "b" "c"] {:coerce {:foo :boolean}})
{:args ["1" "a" "b" "c"], :opts {:foo true}}
user=> (cli/parse-args ["--foo" "1" "a" "b" "c"] {:coerce {:foo []}})
{:opts {:foo [1 "a" "b" "c"]}}
but I can see that the last syntax might not be posix-y, I'm fine with optionally disabling that
I need multiple args for both — in my actual case, I have 0-n “pre-ambles”, and 1+ actual files. Thus the -X foo -X bar file1 file2
is the syntax I hoped to work, without requiring me to remember to add --
and force the parser to stop.
I’d love to tackle this, but will have to look at that code again to see what I can figure out.
[removed bits which were poorly written]
A meander-like matching library that loads fast in babashka:
$ bb -Sdeps '{:deps {sg.flybot/lasagna-pull {:mvn/version "0.4.150"}}}' -e "(require '[sg.flybot.pullable :as pull :refer [qfn]]) ((qfn '{:foo ?foo} [?foo]) {:foo :bar})"
[:bar]
soo…meander doesn’t? (honest question, I’m still new to this)
I had noticed the announcement of lasagna-pull, too, and wondered how it differed from meander… 💭
@U04GFG14FCP Meander also works:
$ time bb -Sdeps '{:deps {meander/epsilon {:mvn/version "0.0.650"}}}' -e "(require '[meander.epsilon :as m]) (m/match {:foo :bar} {:foo ?a} ?a)"
:bar
bb -Sdeps '{:deps {meander/epsilon {:mvn/version "0.0.650"}}}' -e 0.38s user 0.02s system 98% cpu 0.404 total
but it starts in 400ms whereas lasagna starts in an insignificant amount of time💡 thanks!
Thanks for discussing my library here. I did not know meander when I wrote lasagna-pull. From my initial observation, meander is much more complex than lasagna-pull; it is a real compiler from a logical programming background, whereas lasagna-pull is a pure practical effort to try to match Clojure’s map and sequences of maps, which might explain the start time difference @U04V15CAJ observed (or performance) between them.
I send with “write” (as in the example) with current id back to the clj part, and after this closed the connection. Maybe I didn’t find the documentation.. I saw in the tests maybe.. I just want to ask is that possible or not
Does this help? https://github.com/babashka/pods#out-and-err
You can also use the socket transport and then your python program can just print whatever
I would like to catch https://github.com/openai/whisper stdout with babashka. In -verbose mode. Whisper transcribe the audio.. in realtime mainly.. every 8 sec.. you get back the copy.. and I would like to drop to output. See this action
I notice that socket transport isn't that greatly documented, but here is a pod which uses it: https://github.com/babashka/pod-babashka-lanterna
or you can say in the manifest: https://github.com/babashka/pod-registry/blob/a474904c2b964c8212b7b62a773ab97a014a28c3/manifests/org.babashka/lanterna/0.0.1/manifest.edn#L5 and then it will work automatically (but for local development it's easier to use the manual option)