This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-05-13
Channels
- # announcements (8)
- # architecture (11)
- # babashka (159)
- # beginners (112)
- # biff (4)
- # chlorine-clover (4)
- # cider (10)
- # clj-kondo (51)
- # cljs-dev (43)
- # cljsrn (10)
- # clojure (45)
- # clojure-bay-area (5)
- # clojure-europe (11)
- # clojure-france (4)
- # clojure-italy (4)
- # clojure-nl (2)
- # clojure-norway (1)
- # clojure-sweden (1)
- # clojure-uk (8)
- # clojurescript (75)
- # code-reviews (1)
- # community-development (2)
- # conjure (88)
- # cryogen (5)
- # data-science (1)
- # datomic (3)
- # dirac (2)
- # fulcro (4)
- # helix (1)
- # jackdaw (5)
- # kaocha (5)
- # leiningen (2)
- # lsp (49)
- # malli (9)
- # mid-cities-meetup (1)
- # off-topic (8)
- # pathom (3)
- # polylith (19)
- # re-frame (6)
- # releases (3)
- # rewrite-clj (1)
- # shadow-cljs (98)
- # spacemacs (2)
- # tools-deps (6)
- # vim (4)
- # xtdb (6)
What is the idiomatic way to know what was the original task that bb was called with?
@pithyless this is why I wanted to add these :before
and :after
things, but I decided not to add those yet because it wasn't clear what the added value was. Right now I believe there is no way to know this. What is your use case?
Probably some self-inflicted pain. ;] I used the :enter
hooks to log some info about each running task, but I was thinking in CI I want to spew a lot more info about each task (since it's harder to recover the context), but e.g. on my dev machine I may just want to log that the primary task is running (without having all the dependencies logging their info).
I thought I could maybe just use :init
for this, but not sure if there is a reference to a task I can grab at that point?
also FYI, I was surprised this morning about the way :continue
works in shell
. I expected it to ignore the error if passed true
and otherwise call the proc
if one was passed as :continue
Turns out if you pass true
it works as expected, but if you pass a proc
then you deal with all exit-codes (including zero). It makes sense, when you actually read the code for handle-non-zero
but it was surprising nonetheless. Maybe that part of the docs could be revised? I thought of :continue
as "how to handle errors", but it seems the name comes more from "override the default handling logic, ala continuation-passing style code"
the :continue
fn should return either true or false (or some other truthy value), what is surprising there?
re-reading the code now; OK, so I totally misread that part of the codebase this morning
so actually, what I need to do was override what the error-handling code does (the part that throws the ex-info); and I wanted to avoid rewriting a lot of the exit-checking code, but handle-non-zero
is an internal detail of shell
right now without much of a way to override it
so, let me take a step back; if :continue
is either true
or a fn that returns a truthy value, I think the name is fine; it was a misunderstanding on my part
for me the bigger issue, is if :continue
is falsy, I can't change the behavior of the error condition (aside from just catching the ex-info exception)
ideally, I'd like to re-use all the logic of shell
and handle-non-zero
but pass in an alternative operation for the (throw (ex-info ..))
part of handle-non-zero
^ a good example of this is replacing the existing exception handler with something like (line-status/die exit-code "...")
that will both exit the process and print a nice visible warning
this, BTW, is also what lread seems to want to do here - https://github.com/lread/rewrite-clj/blob/main/script/helper/shell.clj - but since he's just wrapping babashka.process/process
he's missing out on the other goodies like automatic tokenize
, etc.
@pithyless gotcha. So maybe we can have an additional :error-handler
function then, which will be triggered on a non-zero exit code or if :continue
returns false?
@U04V15CAJ Yep, that'd be great!
and about the "main" task, what should we do there? we can add back what we had with :dependents
perhaps? if :dependent
is empty, then you know you are the primary task. although with explicit run
this will probably not behave like you think it will?
My original hack was going to be calling tasks->dependees
but I noticed it's commented out for now. You're probably right, that it may not always work as expected, so maybe just #hammock it for now? I don't want to be partially responsible for some not well thought-out features that are going be a maintenance burden :D
Babashka adds babashka.file
to the System properties when you call bb with bb foo.clj
. We could do something similar for run
: babashka.task
or so
or we could add another function babashka.tasks/plan
which returns a map with some information about the execution plan
Both of those ideas sound sensible. The former would be a small overhead to the existing surface area (and would also solve my immediate ask). The latter could potentially have more use-cases, but also more edge-cases. IIRC, the last discussion about an exec plan was halted due to expectations vs non-deterministic ordering in parallel execution.
As for bike-shedding the name for the error handler:
(shell {:error-handler (constantly nil)} "ls foo")
(shell {:on-error (constantly nil)} "ls foo")
(shell {:error (constantly nil)} "ls foo")
(shell {:error-fn (constantly nil)} "ls foo")
You could then write this instead of :continue
:
(shell {:error (constantly nil)} "ls foo")
Another question: should the :error
function determine the result value of shell
or should it just cause side effects (like printing or throwing)
:error-handler
:on-error
:error-fn
:error
^ I think you've just listed all legitimate and/or expected forms for the callback. :) I'm not usually the fan of the standalone version :error
, but in this case I think it works fine (and symmetric to :continue
)I think it's safe to assume, that :error
is the new return value; the caller can easily return proc if that's the intent
if you just decide to re-throw this entire map in an ex-info, then it will behave the same as the original error-handler
handle-non-zero
takes additional opts
from shell; so if we don't pass that on to the handler, it can't use those options
so, not necessarily to continue, but if we call (shell {:foo :bar :error (fn []..) } "ls")
I guess it doesn't necessarily make sense that we would have access to :foo
; and besides you can always wrap that error handler in a closure if you need additional context
Let's go with :error-fn
. :continue
accepts a naked boolean, whereas :error-fn
only accepts a function
$ clojure -M:babashka/dev -e '(babashka.tasks/shell {:error-fn (constantly 1337)} "ls foo")'
ls: foo: No such file or directory
1337
Applied both things on master now. Please test :) Binaries should appear soon in #babashka-circleci-builds
@U04V15CAJ is :babashka/exit
safe to depend on? or should I use (:exit (:proc opts))
?
https://github.com/babashka/babashka/blob/master/src/babashka/impl/tasks.clj#L50
https://github.com/babashka/babashka/blob/5014012bd63dd63fecafc94230dfcce10f2e9490/test/babashka/bb_edn_test.clj#L79
:babashka/exit
is safe to depend on: you can throw an ex-info anywhere in a script and set this value, then bb will exit with this value, if no other code handles the exception
@U04V15CAJ confirming that "babashka.task" and "error-fn" works on my machine. Kudos for the frenzied and selfless work, as always!
> Maybe you can make some `DEV` environment variable which turns off the logging?
Actually, I'm passing around a :task/log-level
in my context so no issue there; what I wanted to solve was can I have an :enter
that logs stuff dependent on the log-level AND if we're now in the primary original task
I guess we can add a :primary
flag to current-task
but what if you have tasks like:
{a :task-a
b {:depends [a] :task :task-b}
b:clean (do (clean) (run 'b)}
When you run b:clean
then b isn't the primary task anymore and I think you still want to treat it as such in some cases?btw, perhaps the b:clean
approach is also a way to deal with your problem: since you can execute something before the task (set some state?) and then run the "primary" task?
I would consider whatever bb XX
was originally called with as the primary task; there just doesn't seem to be a way to hook in and know what bb was originally called with right now, correct?
@pithyless yes, I tried to explain what the problem with this is here: https://clojurians.slack.com/archives/CLX41ASCS/p1620892550258200
for me the run 'b
doesn't really change anything, since it's no longer what the user initiated from the shell; but I can see how the reverse may also be considered true and obvious; so I guess I don't have a really good case to argue here :]
Hi, do you know why i am getting “WARNING: this project requires babashka 1.0.0 or newer, but you have: 0.4.0”?
I had to use future version as an example since it didn't work with other versions in the first version that this feature was added ;)
{:paths ["src"]
:deps {seancorfield/honeysql {:mvn/version "2.0.0-beta2"}
douglass/clj-psql {:mvn/version "0.1.2"}
clojure-term-colors/clojure-term-colors {:mvn/version "0.1.0"}
borkdude/spartan.spec {:git/url ""
:sha "12947185b4f8b8ff8ee3bc0f19c98dbde54d4c90"}}
:min-bb-version "1.0.0"}
babashka 0.4.1 🎉 https://github.com/babashka/babashka/blob/master/CHANGELOG.md#041 Among other tiny updates, babashka linux static is now based on musl and should work on pretty much any amd64 linux version! 🎉 thanks @rahul080327 and @thiagokokada


@U08ALHZ2N what do you do when one of your cloned repos needs updating?
Just manual for now as the diff b/n computers is usually only a repo or two. Could be a useful thing to add down the road
Added a repo update for all repos. Thanks for the nudge on this. Ended up making the tasks data driven
Very nice, I was planning something similar, but for all my dotfiles
a bb.edn with dependencies (e.g. install homebrew before installing things using homebrew) sounds like the perfect use
there’s obviously a bootstrapping problem but with staticallly compiled bb and everything having bash/curl/wget that’s not too much of a barrier 🙂
yeah, I am saying basically: curl babashkainstall && ./bb
is no problem
Yep! https://github.com/cldwalker/osx-setup. I let brew handle brew packages
hah! nice. I actually didn’t know about brewfile, so that solves that part
Does https://github.com/borkdude/rewrite-edn work with babashka?
(shell {:dir "the-path"} "bb my-task")
?Hum not sure cd one would work, since the CI uses on clojure JVM
(apply sh (concat command [:dir dir])
and my command would be something like
["cd" "../my-dir" "&&" "bb" "-m my-project.main"]
no, that won't work as shelling out from the JVM is not the same as executing bash, but you provide :dir
so why not set that to the bb.edn dir?
the dir is dynamic for multiple shell tasks, and this one I want to make using babashka
or (sh "bb" "-m" "my-project.main" :dir (str dir "/../my-dir"))
(but then using proper file system stuff)
it's a common file for multiple tasks, I can't change that code, that's why I can only change the command
one that is dynamic
it's a bit yucky to execute a bunch of shell commands like this, as you can't really see what's going on, unless you print a giant string blob at the end
well, if it's bash, then you can append (cd the-folder && bb the-task)
, the parens start a subshell
but does clojure.java.shell understand the ()
?
like (apply sh ["(cd ../my-dir && bb -m main)"])
It's a Nubank migration tool, that allows you create multiple migrations and we have something like a migration.edn:
{:migrations [{...
:command ["../other-dir/migration.sh"]}
{...
:command ["../my-dir/migration.sh"]}]}
and I'd like to add a new command, but that uses bb with a bb.edn with custom deps like rewrite-edn
The CI/other service kind of parse the edn and call (apply sh (concat command [:dir dir]))
interesting, so let's see how clojure.java.shell/merges :dir
, maybe you can override it
you know, you can just make a bash script which then cds into the right dir and hook that up to your command thing