A wee question on babashka tasks cli support re: opts inheritance and depends ๐งต
Given a bb.edn:
{:paths ["."]
:tasks {foo {:exec-fn tasks/foo}
bar {:exec-fn tasks/bar
:depends [foo]}}}
And a tasks.clj:
(ns tasks)
(defn foo
{:org.babashka/cli {:spec {:foo1 {:coerce :boolean :desc "foo1"}
:foo2 {:coerce :int :desc "foo2"}}}}
[opts])
(defn bar
{:org.babashka/cli {:spec {:bar1 {:coerce :boolean :desc "bar1"}
:bar2 {:coerce :int :desc "bar2"}}}}
[opts])
I see that because bar :depends on foo it inherits its opts:
$ bb bar --help
Usage: bb bar [options]
Options:
--bar1 bar1
--bar2 bar2
-h, --help Show this help
Inherited options:
--foo1 foo1
--foo2 foo2
That's pretty cool, but can I disable inheritance? Or disable inheritance for specific foo opts?You currently can't disable it. Why would you?
Well, let's say I have a compile-js task with options --force, --watch and --test.
And a server task that depends on compile-js. For the server task, --watch and --test are not appropriate.
I don't absolutely have to use :depends, I'm just learning how it works with the new bb tasks cli support.
:depends for :exec-fn works this way so you can pass options for the dependency
If I had your server task, I think I would want to choose I wanted the watch or not?
Hmmm... maybe true... but my --watch isn't currently ready for that.
Let's focus on --test which compiles code for testing, then.
true. so perhaps there should be an inherit option filter or so?
Maybe. Or maybe this is just a characteristic of using :depends with bb tasks cli support.
That said, an :inherit false on --test and --watch would work for my use case. But not sure if that is a good general solution.
I think I'm fine with switching to using run or just calling appropriate code from task.
you could just call the exec fn in your other exec-fn I guess
Yep, or just call the code itself.
that's what I meant, I think?
Ah yes. I thought you meant through :exec-fn somehow. But that's not what you meant! simple_smile
I don't know how you would put something else than just one symbol in :exec-fn
but perhaps you found a secret level
No, no. If I can misunderstand, I will!
damn, I was hoping for the secret level
Ha! There might be one! Somewhere! Hey, the bb task cli support is really nice, btw. I tend to refer to your https://github.com/babashka/babashka/blob/master/doc/adr/ai/0001-cli-support-in-bb-tasks.md, not sure if it is documented for users yet? Should it be covered in babashka book? If so, can try to help with that, if you like.
yeah this is an ai document that I don't want to bother users with, it's just a document that records why I chose certain things. the essential info is in my blog since this was experimental 2 months ago or so. But I think it should now go into the book soon
Oh there is some coverage: https://book.babashka.org/#cli
yes, but not with the most up to date info that is recorded in 2 or.3 blogs over the past few months
True. Let me know if/when you want some help with that.
I'd be delighted with some help! The blogs are: โข https://blog.michielborkent.nl/babashka-1.12.215.html โข https://blog.michielborkent.nl/babashka-tasks-cli.html โข https://blog.michielborkent.nl/babashka-ffi.html โข https://blog.michielborkent.nl/babashka-1.13.222.html TUI/JLine + FFI could just be a reference / callout to the library probably? But tasks doesn't have a library/reference other than the book
Lemme know if you'd like an issue for controlling inheritance of opts.
I wonder if a global :inherit false could be interesting for some projects. I probably would have used that for cljdoc if it were available.
a global {:cli {:inherit false}should work already?
no sorry forget about that
Another idea: for passing options to dependencies, we could prefix them with the task's name:
bb server --compile-js/watch falseof course this doesn't solve your "I don't want this at all" problem, but it does disambiguate more
Yeah... that's an idea. But I think the --help is also important. It should only show relevant options.
(BTW, I'm not stuck at all, I resolved by not using using :depends for now).
yeah, it did dawn on me that the dependency may have the same option name with a different coercion so passing an option to the top level task may then throw when it calls the dependency
there is some detection of conflicting inherited options...
alias conflicts are checked
but with two options with different specs, the top level coerce wins and then when the dependency gets the "wrong" coerced value, it will crash (depending on what the code does with it)
Maybe an explicit inherit is the cleanest:
{:tasks {:cli {:spec {:env {:coerce :keyword :default :dev}} :inherit [:env]}
-jar {:exec-fn build/jar}
deploy {:depends [-jar] :exec-fn deploy/run :cli {:inherit [:snapshot]}}}}so each top level task declares what options can be passed to its dependencies?
that would solve both your problem and the ambiguity is on the user
sound good? decision matrix worthy? or obvious?
So, would the inheritor decide which opts to inherit? (Have I read your example correctly?)
yeah
as in: allow the user to also pass these extra options for deps
and not setting won't inherit anything
No inherit by default sounds like a nice default.
On your :cli above what does :inherit [:env] do? since :cli has no :depends?
:cli is the global settings so every task inherits :env from whatever declares it
Oops sorry, brain fart.
yeah no that example is weird, forget about that one
Ah right, it is the depender not the dependee that determines inherits... so yeah, maybe not good example.
Might be worth a decision matrix. I'm kinda focused on my little use case. But a broader think could be useful.
ok, problem statement: non-opt in inherited opts from deps can cause 1) bugs/conflicts with different coercions, 2) some people don't want the automatic dependency options at all.
C1. principle of least surprise (syntax should be clear, no magical behavior)
C2. 1 is solved
C3. 2 is solved
C4: ...
S1 Explicit :inherit . C1: ๐ (inherit word is already used in :cmd ) C2. ๐, C3, ๐
S2: Maybe S1 with another term?
โ โ โ โ S3 dep exposes upward (:expose โ S4 automatic merge + โ S5 qualified keys โ S6 status quo + โ
โ โ S1 :inherit on target โ S2 S1, other word (:propagate) โ [:snapshot]) โ :propagate false + conflict โ --jar/snapshot โ conflict error โ
โ โ โ โ โ error โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ C1 least โ ๐ก word already used by :cmd, but same โ ๐ก new word for a thing :cmd โ ๐ก target's --help grows from โ ๐ด options still appear โ ๐ด private deps become CLI โ โ
โ surprise, no โ meaning: owner declares, what runs under โ already names; two words, one โ something another task declared โ from nowhere unless turned โ surface; ---jar/ naming โ ๐ด unchanged โ
โ magic โ it receives โ concept โ โ off โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ C2 coercion โ ๐ข one entry per key, the target's; target โ ๐ข same โ ๐ก two deps exposing one key still โ ๐ก error, but the collision โ ๐ข each key names its task โ ๐ก error only โ
โ conflicts โ vs dep mismatch is an error โ โ collide; error needed โ stays easy to hit โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ โ ๐ข default; :tasks {:cli {:inherit true}} โ โ ๐ก opt-out per dep, not per project, โ โ ๐ด no switch; unqualified โ โ
โ C3 opt-out โ for the old behavior โ ๐ข same โ unless a runner-level switch is โ ๐ข switch โ keys still flow โ ๐ด โ
โ โ โ โ added โ โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ C4 consistent โ ๐ข same key, same direction, same two โ ๐ด diverges from :cmd on purpose โ ๐ด opposite direction โ ๐ก unrelated to :cmd โ ๐ก orthogonal โ ๐ก โ
โ with :cmd โ forms โ โ โ โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ C5 help and โ ๐ข one description, one default per โ ๐ข same โ ๐ก description comes from the dep โ ๐ก last dep wins silently โ ๐ด every dep option listed โ ๐ก โ
โ completion โ option, declared where help is printed โ โ โ โ twice, plain and qualified โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ C6 breaking โ ๐ด bb deploy --snapshot needs :inherit on โ ๐ด same โ ๐ด needs :expose on -jar โ ๐ข none โ ๐ข none โ ๐ข none โ
โ โ deploy โ โ โ โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ โ ๐ก a dep used by five targets: five โ โ โ โ โ โ
โ C7 repetition โ :inherit lines; borrowed entries keep them โ ๐ก same โ ๐ข declared once, on the dep โ ๐ข none โ ๐ข none โ ๐ข โ
โ โ short โ โ โ โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ C8 extensible โ ๐ข per-dep map {-jar [:snapshot]} and S5 โ ๐ข same โ ๐ก target-side opt-out can be added โ ๐ก selection means a second โ ๐ข โ ๐ก โ
โ โ both fit later โ โ โ knob โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโค
โ โ ๐ก new default, borrow merge, conflict โ โ โ โ ๐ด parser change in โ โ
โ C9 size โ check, docs โ ๐ก same โ ๐ก same plus a new key โ ๐ข small โ babashka.cli, help, โ ๐ข tiny โ
โ โ โ โ โ โ completion โ โ
โโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโWoah! That was fast!
I typed my ideas in a ๐ค - feel free to criticize though
it seems S1 is the least bad option so far
don't care much about breaking here since it was announced as experimental
@seancorfield is using this already (I'm too) but I'll warn him about the change
So does S1 mean opts inheritance config is for the invoked task only? If a depends on b depends on c and d depends on e...
hmm, you mean, you should specify from which dependency you inherit? because there might be multiple overlapping? yes, good point :-s
Another option: never inherit options. Too complicated! ๐
Whoa... catching up...
that was a few versions ago but I decided to bite the bullet since I needed this ;)
So, inheritance is required IMO for some situations so "never inherit" isn't an acceptable solution.
I would prefer an option to locally disable it per task that was "off" by default (i.e., inheritance is the default, but you can turn it off).
I think something in :depends to turn off inheritance of options feels like the right approach, since this is about how :depends works, rather than how an individual task works.
Perhaps some new syntax that allows you to depend on task but explicitly not pass through the options, or not merge the specs?
Its a bit tricky when a depends on b depends on c... no?
I guess the source of issues is that different dependencies can have overlapping names with different specs so it's ambiguous which one you're inheriting
maybe: :inherit [-jar/snapshot]
but what if both -jar and -pom have :snapshot :)
I a inherits b c and d and they they all have :force in their spec, they all get :force?
maybe a rule in bb exec-fns should be that you should not be using options names that mean different things ;)
that could be reasonable within the scope of a project
In tools.build tasks, they take a hash map of options, and it's common to -> options through a bunch of tasks so passthru is sort of the expected default there.
I was expecting that behavior in bb tasks via :depends but it initially didn't do it, and that (recently) got changed so they do passthru like -> (is that accurate @borkdude?).
yes
(or maybe it worked in some situations but not all?)
well, that's the idea
But, yeah, my mental model is -> just like tools.build tasks.
Do you use :restrict Sean? I like a strict cli.
yeah I think :cli {:inherit [:snapshot]}} is reasonable,
@leeโs concern about passing :force to all dependencies may be a reason to rename your options to something more explicit?
I only added CLI specs because that was a workaround @borkdude suggested for a lack of inheritance in my initial setup.
Not sure. Let's say that --force means don't use the cache and force a rebuild. Makes sense from many tasks maybe?
This all came about because I was adapting an existing tools.build setupโwhere all options thread through all tasksโto use bb instead and :depends and I expected the same behavior.
I've tended not to use :depends myself Sean, so nice to have someone here who uses it plenty.
For me, right now, I'm leaning toward just being super explicit and calling dependent task code directly.
But I might use :depends if there were a global switch to turn off opts inheritance.
:depends is nice for when dependencies also can depend on each other, it de-duplicates the work. like if a depends on b and c and b depends on d and c depends on d, d would be executed only once.
If the current behavior silently changes, it would break my projects' existing CI pipelines, potentially in unsafe ways (i.e., they might do the wrong thing instead of "failing"), so I would urge that whatever changes are made, the current default behavior stays the sameโso nothing breaks ๐
I'm all for more optional control over the behavior, however.
What about my original snippet above, Sean? Are you finding your tasks --help are documenting irrelevant opts?
@seancorfield the :exec-fn stuff is a bit experimental (documented as such in my blogs) and I'm now locking down that behavior (and I was going to warn you about it) ;).
since I now discovered that automatic inheritance can cause trouble (but only if you have same-named options with different specs) and @lee leans towards not wanting the inheritance automatically, I might re-consider before making it final.
@lee I'm not finding problems with --help because the options are relevant in my situations ๐
Personally? I'm ok with it being on by default if I can turn it off in my :cli base-opts.
@borkdude If you make non-inherit the default, would I be able to add the new "please inherit" syntax now to my projects and the existing version of bb/CLI will silently ignore that new syntax? Or will it break?
I'm concerned that I won't have a safe path to the new behavior...
(and full disclosure: I deliberately have CI set to use the latest Babashkaโso I guess another option for me is to update all of my CI .yml files across all of my projects to pin bb to 1.13.222 but, ugh!)
I have to think about this but I will give you the syntax that will work with 222 and 223
before publishing
I suppose... in my compile-js example above with task-specific opts --test and --watch I could contrive my tasks to never have opts that are not relevant to up the hierarchy somehow... so I might have compile-js-test, compile-js-watch tasks to avoid those opts. Do you have some strategy Sean? Or did things just happen to work out for you?
I still think the current behaviorโmimicking ->โis the most intuitive and mirrors what folks would already be doing when chaining tools.build tasks. But now I'm repeating myself.
Maybe a link to your current bb.edn would help, @seancorfield
It's totally worth repeating oneself to stress a point! simple_smile
HoneySQL, next-jdbc, rephrase all rely on this. Can't link you to work stuff, but it also relies on it now that I'm using bb to power my build.clj workflows.
Although next-jdbc uses :depends it doesn't seem to use babashka cli specs for opts.
Ah was looking at your bb.edn
Like I said above, I only added that as basically a workaround from Michiel for option passthru not working "as expected".
Oh yeah, my bad eyes, there it is, apologies.
I used to have nasty, explicit (run '-snapshot) calls in various places and a -snapshot task that parsed *command-line-args* for a snapshot string. I didn't realize I could just use --snapshot and it would "do the right thing" ๐
With CLI specs, I expect I could clean up all the existing arg parsing in test too but I didn't know about that when I wrote all this stuff and it's in several of my projects and... well... It. Just. Works. today.
And, if I did do that, I would still want all of those options to be inherited from bb ci or bb ci:deploy invocations. So, again, -> is the default behavior I want here ๐
Two votes from your user base, borkdude: 1 indifferent so long as there is an off switch, 1 strongly for retaining current behaviour Not a big sample size, but there you have it.
right, and keeping stuff as is is always a good thing in clojure I guess
I guess people should only be aware of not having spec options that can conflict in meaning and that they are passed to dependencies as well
Yes, it is an expectation even for features marked experimental!
Once behavior is in an official release, someone out there will be using it ๐
Hey, you're talking to the guy who already has Clojure 1.13 Alpha 7 on his staging servers at work!
but yeah... I liked the default, that's why I added it, but I hope people don't get burned by this automatic passing of options like --delete to a dependency called harddrive
I hear some folks are even using clojure/spec.alpha in production!
Hmm, only for over a decade, I think? ๐
(okay, that may be an exaggeration but it's been seven years since my blog post about how we use Spec at work!)
but yeah with tools.build you get a similar issue (-> {:clean true) (pom) (clean-harddrive-root))
true
(re: Spec... Clojure 1.9.0 Alpha 1 introduced Spec in May, 2016 so we probably have been using it for a decade in production! I wasn't exaggerating, apparently)
Madcaps!
Re: threading tools.build tasks, yup, and so you have to be careful to have more explicit option names if that matters.
And for bb tasks, you can get full control by turning off inheritance (in a future release) and wiring things up yourself. You'd lose the neat auto-de-dupe task of work, but...
(-> {:launch true} (browser) (rockets)) ๐
Eek!
yeah man, open world, accept extra arguments, what could go wrong
A couple of examples from our build.clj file at work:
(defn tag-build-and-upload
"What it says on the tin!"
[params]
(-> params
(assoc :prefix "build")
(tag-and-push)
(assoc :since "previous-release")
(build-uberjars)
(upload-uberjars)))
and
(defn start [opts]
(-> opts (poly-check) (check-all) (ancient) (cve-check) (run-bb-task "splint") (cold-start)))And we also have
(defn run [opts]
(persistently (-> opts (database-setup) (test-stable) (build-uberjars))))
and run build.clj in a REPL so we can do (-> {} start run)@lee so to your problem: to avoid inheritance, you can just not use :depends for now. Do you need more options?
I guess your just posted issue is also related:
https://github.com/babashka/babashka/issues/2151
what should the exec-fn receive here when someone types: bb baz --option-for-bar
No immediate need. Would be nice to have a global off switch, but not essential.
my initial reaction would be: yes, it should pass those options
(at least to be consistent?)
I guess so. Did not test exec-fn depending on :task, did I? What should happen there?
the other way around: no options are passed, since task can do anything with command line args. I guess the reverse is also true, which is an argument for not passing / parsing options
If you're dealing with *command-line-args*, you're not in "options" land, you're in sequence-of-strings land...
yes, and bb can't check that for you, so anything out of options land that isn't called directly on the command line, won't get the opts except for it's default arguments (exec-args or cli defaults)
Q: in bb.edn, is there any point/benefit of specifying an org.clojure/clojure dependency in :deps?
I'm updating deps-new and noticed that I have this in the generated bb.edn files, and cannot remember why I did it:
:deps {org.clojure/clojure {:mvn/version "1.12.6"}}No benefit
Thanks. I will remove it.
It seems like babashka ships with libffi, but doesn't include the libffi calls as part of its native image downcall reachability metadata https://github.com/babashka/babashka/blob/8daf6378bbabaf9dd87972144ab3baf3e25ec256/resources/META-INF/native-image/babashka/ffi/reachability-metadata.json#L3. Is that right?
true, this needs some work that I haven't done yet
you want to use libffi on native-image, right?
I can fix that later this week probably
I'm just curious. I remember you mentioned that the libffi calls were slower. Including the metadata seems like it should speed things up.
I'm prepping for my fast, lean, native clojure workshop and am trying to catch up with all the cool stuff in babashka.ffi ๐
oh sorry, libffi.... I had bb.ffi in my head
I was talking about libffi via bb.ffi
in babashka
oh, the libffi bindings use the native image specific API rather than FFM, https://github.com/babashka/babashka/blob/8daf6378bbabaf9dd87972144ab3baf3e25ec256/src-java/babashka/impl/Libffi.java#L12.
ok, nevermind
I just assumed that the libffi bindings used bb.ffi
and generated the required classes at compile time
right. yes. so in bb there are a number of pre-compiled shapes that are made fast with the native image C API (`@InvokeCFunctionPointer` s in src-java/babashka/impl/FfiTrampoline.java
the guide calls these trampolines.
The shapes that are not covered by the trampolines go through libffi @CFunction bindingsin src-java/babashka/impl/Libffi.java
The other option in native image is to use an FFM Handle, but those are slower (3.5 ยตs compared to libffi at 1ยตs compared to trampoline at 30ns)
are the FFM handles 3.5 ยตs even with the downcall metadata?
yes, without the metadata they don't work at all
ah
for the JVM: bb.ffi has gotten performance PRs recently which makes https://github.com/andersmurphy/sqlite4clj run faster than with coffi (I've heard someone here in #CLX41ASCS say)
Interesting
but I'm delighted to learn that you are giving some attention to bb.ffi / libffi in your talk. let me know if you have other questions. there are a couple of fun demos in http://github.com/babashka/ffi/examples
I wish I could attend your workshop but I have to go to a meeting that afternoon (which is also fun, but can't be in multiple places), else I'd loved to attend
yea, I think the bb.ffi features have a lot of exciting potential!
I expect you noticed it already @smith.adriane, but https://github.com/babashka/babashka.esbuild is a nice example that helped me learn a bit about how things can work.
ah yes, and there's https://github.com/babashka/babashka.sqlite (check out the clojure callback example!) and https://github.com/babashka/babashka.duckdb too
this one's also neat: https://github.com/babashka/filewatcher it does not require any libs besides those already on your OS
(native libs that is)
neat!
another potential for speedup might be to replace the MethodHandle calls using invokeWithArguments with invokeExact, but that does require writing java byte code.
that's already what happens on the JVM in bb.ffi (for the fixed scalar path using the Class-File API), not for structs by value or varargs
for the other cases: https://github.com/babashka/ffi/issues/44
Can you explain what the actual, observable change from #2151 is?
yes.
{:tasks {b {:exec-fn tasks/my-fn}
a {:task (+ 1 2 3) :depends [b]}}
bb a
Before: task b didn't run
Now: b runs but only with its own defaultsWhoa, the b task did not run at all?
yeah, that was the bug
or, oversight
And bb a --foo does not pass {:foo true} to tasks/my-fn in this case?
true
since a is not in "option" land
I guess it's a rare combination. Personally I'd make task a an exec-fn too
Okay, so tasks written with :exec-fn and tasks written with :task don't really play nicely together...
If I had bb x --foo where x is :exec-fn and :depends on y, but y is :task and depends on z, which is :exec-fn, the intermediate task (`y`) "breaks" the options pass through because it's not an :exec-fn? Just to clarify.
if the entrance is an exec-fn you're parsing the command line args anyway in a bb.cli compatible way so that whole chain works
Ooh, that's a bit subtle!
but yeah, :task is the "old" way of doing things and :exec-fn is the more declarative + bb.cli completions way of doing stuff. I guess plain tasks can just work but just don't manage command line args yourself in that case
I'll have to have a deeper think about how I currently deal with multi-version testing etc since I've relied on *command-line-args* so much and my own explicit parsing ๐
you can still do that if you want
there's nothing wrong with that, exec-fn is opt-in
It's always felt a bit clunky. I just wasn't aware of the "better" approach until recently.
this approach is only 1.5 months old :)
A lifetime in software! ๐
this is when it got announced: https://blog.michielborkent.nl/babashka-tasks-cli.html
Really tho', you only added :exec-fn that recently?
bb tasks did have (and still has) (exec 'tasks/fn) as a dynamic expression to invoke a bb.cli-speced function. but I wanted to get completions so I had to make it more declarative using a plain EDN value
completions + automatic help
that's basically what you opt into with :exec-fn
Thanks. I'll bookmark that article and come up with a better CLI "language" for dealing with multi-version testing etc. Now that I can put task impls in build.clj, it'll be easier to switch to :exec-fn stuff.
yes. and for the record, you could always already put functions in a code file and call them from tasks and use bb.cli with that, through :task (exec 'tasks/my-fn) since years. :exec-fn is just a "better" version of that.
Yeah, but I think my brain never made the connection that CLI options got passed implicitly there.
(the docs still need to be updated with what I describe in the blog, but the above link is the older stuff)
That's a lot of docs to read ๐
if it's too much, just point a robot at it and let it summarize ;)
https://github.com/seancorfield/honeysql/blob/develop/bb.edn -- now only using :exec-fn! Thank you for the push in this direction!
really loving your hard work @borkdude, thanks!
Seconded, yes, it's amazing work! I really do appreciate it, as well as your willingness to educate bb newbies like me! gratitude
rephrase has also been updated to only use :exec-fn and tasks moved to build.clj. This is very nice.
hmz, after a night's sleep I realized that my thinking on plain task -> exec-fn is inconsistent, since you're also opting in on :exec-fn that way for the first time, so parsing args is expected there as well without breaking anything
but hmm, --help probably doesn't make sense for a plain task, so perhaps it's enough of an edge case to leave it
next-jdbc has also been updated to only use :exec-fn. This one needed more options, but was still pretty straightforward. Again, thank you!