babashka 2025-12-22

A reflection to accompany bb-timemachine. Babashka has put me truly in control of my environment. I now script things consistently rather than "remember shell commands". And it doesn't even cost more time! A REPL with p/shell and fs/[all the nice things] is all I need. And I get real data rather than lines of text. That means I can keep growing the little seeds of shell scripts into useful namespaces if the problem at hand is important. bb-timemachine grew out of this attitude. Try make our days a little bit nicer. You all might be better served copying what you want from the 50 lines of implementation rather than using the dependency! Dependencies may act as a barrier against learning.

❤️ 7

this might be pretty cool to run benchmarks with, and run some comparison against the results (like in golang, you'd use a tool called benchstat). Or, use it to build a pair of binaries for a tool at different hashes and subsequently run them with hyperfine. ✨

🔥 1

I actually think I will use bb-timemachine at some point to clean up my current script! It looks like a nice abstraction 👏

❤️ 1

Glad you like it! I stumbled into the API design. First, just take a function and "run it in the past". Then, do the same for arbitrary shell commands. I expected to have to hard-code knowledge of how to run the tests, but then I didn't!

Yeah that's really nice. I think it will not be much work to update my script. It will replace these lines and is probably much faster https://gist.github.com/jeroenvandijk/10aa1a7ef82e15be689f5af34f387079#file-test-clj-L56-L73

It is definitely faster than 6 seconds, at least for our code base at work! I don't personally notice the difference between a local folder with a fresh JVM. One thing to watch out for is you only get tracked files copied over, but that's probably the case for test suites already running on CI.

Yeah i think that's what I would want. I'll let you know how it compares once I get to it

💯 1

Ok I did a quick test. It is very fast, insignificant overhead. The only thing is that it doesn't take my submodules into account. I will try to find out if there is something that you can do with worktree that supports this

👍 1

Maybe something like this?

(timemachine/do-at "HEAD"
  (fn [dir]
    (p/shell {:dir dir} "git submodule update --init --recursive")
    (into #{}
          (map fs/file-name)
          (fs/list-dir dir))))
;; => #{"example"
;;      "README.md"
;;      "LICENSE"
;;      "bb.edn"
;;      "src"
;;      "tests.edn"
;;      ".gitignore"
;;      "deps.edn"
;;      ".git"
;;      "test"}
I haven't tested with real submodules, though, so not sure if it'll actually work.

Very elegant! It sort of works except for the cleanup part

16: (defn worktree-remove [dir worktree]
17:   (p/shell {:dir dir :out :discard :err :discard}
      ^--- fatal: working trees containing submodules cannot be moved or removed

18:
But I guess that can be fixed. Time wise unfortunately it is the same as before so it seems the submodule checkout is the culprit. I can imagine it can be done a bit faster when done locally, but I'll have to do some research for this. Either way the extra time was never a big issue for me. I like your approach so will probably migrate to it when I figure the submodule thing out

Right, probably requires a bit more work then. Glad we at least were able to pinpoint the culprit of those 6 seconds!

Last attempt for today!

(defn ^{:indent 1} do-at-auto-submodule
  [git-revision handle-fn]
  (let [tempdir (fs/create-temp-dir)
        repo-dir "."
        sha (rev-parse repo-dir git-revision)
        worktree-dir (str (fs/file tempdir sha))]
    (worktree-add repo-dir worktree-dir sha)
    (try
      (p/shell {:dir worktree-dir} "git submodule update --init --recursive")
      (handle-fn worktree-dir)
      (finally
        (p/shell {:dir repo-dir :out :discard :err :discard}
                 "git worktree remove" worktree-dir "--force")))))

(do-at-auto-submodule "HEAD" #(->> % fs/list-dir (map fs/file-name) set))
;; => #{"example"
;;      "README.md"
;;      "LICENSE"
;;      "bb.edn"
;;      "src"
;;      "tests.edn"
;;      ".gitignore"
;;      "deps.edn"
;;      ".git"
;;      "test"}

❤️ 1

Putting away the computer for now, hope you get the submodules under control!

Thank you Teodor!

🙌 1

With --force it doesn't complain anymore. And when i add --no-fetch to the submodule command it is also much faster. 2 seconds now. So that's nice!

git submodule update --init --recursive --jobs 8 --no-fetch

💯 1