babashka

Casey 2025-07-09T10:37:35.530859Z

I have some clj files that implement some common/shared tasks that I use in many of my bb.edn files. Usually I just copy/paste the scripts/ dir and bb.edn around, but I'd like to be able to manage those task scripts in one place. What's the best way to go about doing that?

Casey 2025-07-09T10:38:08.209699Z

Here is a minimal sort of bb.edn to give you an example:

{:paths ["scripts"]
 :deps  {io.github.paintparty/bling {:mvn/version "0.4.2"}}
 :tasks {
         build-assets {:task (exec 'assets/.-main)}
         datomic      {:task (exec 'datomic/-main)}}}
the scripts dir has assets.clj and datomic.clj, and they dep on the bling lib

borkdude 2025-07-09T10:38:26.776749Z

Sure, you can put your code in a library and just use the library. You still have to hook up the library to the task names though

borkdude 2025-07-09T10:39:24.913269Z

So in addition to bling you would have another library

Casey 2025-07-09T10:39:30.265759Z

{:deps  {io.github.paintparty/bling {:mvn/version "0.4.2"}
         myns/shared-scripts        {:mvn/version "0.0.0"}}
 :tasks {
         build-assets {:task ??}
         datomic      {:task ??}}}

borkdude 2025-07-09T10:39:52.133419Z

yeah, you don't have to put it on mvn though. it can be a local/root or git/url+git/sha lib

๐Ÿ‘ 1
Casey 2025-07-09T10:40:25.657469Z

can the :task value can just be normal clojure code like :build-assets {:task shared-scripts.assets/-main} ?

borkdude 2025-07-09T10:40:46.814129Z

yes

Casey 2025-07-09T10:41:33.044909Z

ah nifty! I assumed it was something special I guess. Is there a way to provide the :task and :doc from the library?

borkdude 2025-07-09T10:42:00.100229Z

no, unfortunately not, although doc will be derived from the var I think, if you just use the symbol

Casey 2025-07-09T10:42:09.288179Z

:build-assets shared-scripts.assets/task-def ? which is something like (def task-def {:task ... :doc ...})

borkdude 2025-07-09T10:42:23.334269Z

the task names are always static

Casey 2025-07-09T10:43:05.643679Z

gotcha, ok, that is probably good enough, the key is that something useful shows up in bb tasks

Casey 2025-07-09T10:43:13.239209Z

thanks @borkdude I will give this a spin

๐Ÿ‘ 1
Casey 2025-07-09T11:34:16.982199Z

This works quite well!

Casey 2025-07-09T11:37:26.469059Z

One thing I might like to do is use data defed in the bb.edn file:

{:deps  {mylib/tasks {:local/root "../../some/path/tasks"}}
 :tasks {:init       (do
                       (def css-build-opts {:input  "resources/public/main.css"
                                            :output "resources/public/compiled.css"}))
         asset-build mylib.tasks/css-main ;; <-- this function gets cli args but cannot access css-build-opts

         asset-build2 {:task (mylib.tasks/css-main css-bild-opts *command-line-args*)
                       :doc  "Have to manually copy the docstring"}}}

borkdude 2025-07-09T11:41:20.946309Z

now you only have to copy your bb.edn instead of also your code

Casey 2025-07-09T11:48:27.712669Z

fair enough

Casey 2025-07-09T15:48:02.280189Z

Do you have any plans to support dynamic tasks or loading tasks from deps?

borkdude 2025-07-09T19:42:25.320469Z

I consider it a feature that all tasks are statically known for people glancing the bb.edn (similar to aliases in deps.edn )

๐Ÿ‘ 1
gaverhae 2025-07-09T14:19:34.667229Z

I've just started on the path of using babashka instead of Bash scripts. (That was hard. I've spent about 5 years with Bash as my primary language in my last job so I'm pretty comfortable with it, and somewhat skeptical of replacing it. But I want to give it a go.) I'm stuck at what I'm guessing is a very-easy-to-fix PEBKAC: how do I construct new paths?

โœ… 1
gaverhae 2025-07-09T14:20:00.793979Z

I have:

#!/usr/bin/env bb

(ns t
  (:require [babashka.process :as p]
            [babashka.fs :as fs]))

(def dir (fs/parent (fs/parent *file*)))

(defn compress
  []
  (let [data-dir (
What do I type now to get the equivalent path of "$DIR"/_data?

dpsutton 2025-07-09T14:21:20.354749Z

user=> (apropos "path")
(babashka.classpath/add-classpath babashka.classpath/get-classpath babashka.classpath/split-classpath babashka.fs/exec-paths babashka.fs/path babashka.fs/path-separator babashka.fs/real-path babashka.fs/split-paths babashka.wait/wait-for-path clojure.core/*compile-path* clojure.core/*source-path*  clojure.zip/path selmer.parser/known-variable-paths selmer.parser/set-resource-path!)
user=> (doc babashka.fs/path)
-------------------------
babashka.fs/path
([f] [parent child] [parent child & more])
  Coerces f into a Path. Multiple-arg versions treat the first argument as
  parent and subsequent args as children relative to the parent.
nil
user=> (babashka.fs/path "/tmp" "trace.snowflake")
#object[sun.nio.fs.UnixPath 0x4335fbfd "/tmp/trace.snowflake"]
user=>

dpsutton 2025-07-09T14:21:44.903219Z

ask the runtime for things related to paths, get a docstring of one that looks promising, check it in the repl

Darin Douglass 2025-07-09T14:21:57.035239Z

(let [data-dir (fs/file dir "_data")]
  ...)

gaverhae 2025-07-09T14:22:08.600419Z

Oh. Thanks!

dpsutton 2025-07-09T14:22:32.355309Z

(i truly think apropos and doc are phenomenal tools that are default in the runtime)

๐Ÿ’ฏ 1
gaverhae 2025-07-09T14:22:43.969809Z

I was looking at https://github.com/babashka/fs/blob/master/API.md#babashka.fs/path and the description at the top ("Coerces f into a Path.") did not hint at that at all.

borkdude 2025-07-09T14:23:26.799799Z

oh you mean multiple args to fs/path?

gaverhae 2025-07-09T14:23:41.503329Z

Yes, I completely missed that.

borkdude 2025-07-09T14:24:00.907649Z

does that too. Probably I didn't mention it because I was so used to it. Let's fix that right away. Thanks for trying bb :)

gaverhae 2025-07-09T14:24:27.945129Z

I never knew that about either ๐Ÿ˜ฎ

gaverhae 2025-07-09T14:24:59.964919Z

Do you want a PR or is it easier for you to fix directly?

borkdude 2025-07-09T14:25:04.779639Z

yeah. much better than string wrangling with "/" , more portable between OSes too

borkdude 2025-07-09T14:25:11.761329Z

Oh PR would be sweet!

gaverhae 2025-07-09T14:27:25.410829Z

Are the docs generated somehow or is editing the md file directly the right approach?

gaverhae 2025-07-09T14:29:12.336939Z

https://github.com/babashka/fs/pull/149

borkdude 2025-07-09T14:31:58.652189Z

docs are generated from the var docstrings using bb quickdoc

gaverhae 2025-07-09T14:40:47.446329Z

๐Ÿ‘€

borkdude 2025-07-09T14:42:56.013529Z

so the docs are in the docstrings in the code

borkdude 2025-07-09T14:43:20.642549Z

and then extracted and frobnicated into a .md file

borkdude 2025-07-09T14:45:42.019679Z

tl;dr: just update the docstring in the code, that will do, don't worry about anything else

gaverhae 2025-07-09T14:45:44.618719Z

Yep, following that. So the information I was missing is in the docstring, but not in the first sentence, which is why it wasn't at the top.

borkdude 2025-07-09T14:45:57.730129Z

oh...

gaverhae 2025-07-09T14:46:06.008289Z

Because quickdoc https://github.com/borkdude/quickdoc/blob/main/src/quickdoc/impl.clj#L37 for the summary at the top.

Samuel Ludwig 2025-07-09T14:47:47.765129Z

a little too quick

gaverhae 2025-07-09T14:48:22.951669Z

I've updated my PR.

borkdude 2025-07-09T14:49:31.223059Z

Much better than it was. I think we can now delete the second sentence, do you agree?

gaverhae 2025-07-09T14:50:19.120819Z

I think I would be fine without it, but it does add more precision, so really up to you.

gaverhae 2025-07-09T14:50:28.873099Z

Happy to remove it in my PR if you think that's the right call.

borkdude 2025-07-09T14:50:51.732989Z

I'll merge it, you've been through enough as a fresh bb scripter :)

borkdude 2025-07-09T14:51:24.096559Z

โœ…

gaverhae 2025-07-09T14:51:39.547149Z

Thanks!

gaverhae 2025-07-09T15:10:36.421379Z

Is there an equivalent to Python's if __name__ == "__main__"? I'm feeling a desire for a REPL-connected workflow, and that requires not running my currently-top-level "main" action on file load. The file in question is meant to replace a Bash script, so ideally it's called directly with a shebang (that currently works, but with top-level side-effect) and does not have a name ending in .clj. Open to the notion I'm holding it wrong.

โœ… 1
borkdude 2025-07-09T15:13:15.057489Z

Yes search the babashka book for Python, afk now :)

gaverhae 2025-07-09T15:13:44.348479Z

Got it, thanks! I'd searched for "shebang", didn't think of searching for Python ๐Ÿ™‚

๐Ÿ‘ 1
borkdude 2025-07-09T15:14:00.209459Z

http://book.babashka.org itโ€™s somewhere in there

gaverhae 2025-07-09T15:14:12.211889Z

Yes, I have found it:

(= *file* (System/getProperty "babashka.file"))

gaverhae 2025-07-09T15:30:19.446019Z

babashka.fs/match has four options, with no documented default value. The code does give them (implicit) default values. Would a PR adding the default values to the docstring be accepted, or is the omission deliberate? (i.e. they are implementation details)

๐Ÿ™ 1
โœ… 1