babashka

https://github.com/babashka/babashka. Also see #sci, #nbb and #babashka-circleci-builds .
2021-01-12T08:17:19.088700Z

I have a couple of small scripts, all in the root of my scripts folder. It looks like I could factor out some code into a reusable part. What's the best way to require that reusable part in the scripts that use it? (add-classpath ...) and then (require '[...])? I'd prefer not to create a project structure if possible... just one flat script folder.

borkdude 2021-01-12T08:47:16.089300Z

@mmz you can add "." to the classpath and then you can just require from the flat script folder

borkdude 2021-01-12T08:50:03.090200Z

provided that you use only one namespace segment. babashka does expect foo.bar to be in foo/bar.clj

borkdude 2021-01-12T08:50:54.090700Z

so you could use underscores like (ns foo_bar) if you want to keep it flat

borkdude 2021-01-12T08:53:53.091100Z

or (ns foo-bar) actually, and then code will be in foo_bar.clj

borkdude 2021-01-12T08:54:01.091300Z

both should work

2021-01-12T08:54:28.091800Z

Thanks! Will try and will keep you posted.

borkdude 2021-01-12T08:57:29.092200Z

btw load-file also works, if you don't want to use the classpath

1
borkdude 2021-01-12T08:57:39.092400Z

so lots of options =)

2021-01-12T08:59:37.092700Z

works!

2021-01-12T08:59:52.092900Z

Thanks ๐Ÿ™‚

2021-01-12T09:00:06.093300Z

Is load-file shorter?

2021-01-12T09:01:18.094100Z

Current test: dep.clj:

(ns dep)

(defn double [x] (* 2 x))
test.clj:
#!/usr/bin/env bb

(require '[babashka.classpath :refer [add-classpath]])
(add-classpath ".")
(require '[dep])

(println (dep/double 4))

2021-01-12T09:07:02.095100Z

That's even better! ๐Ÿค“ test.clj:

#!/usr/bin/env bb

(load-file "./dep.clj")

(println (dep/double 4))

2021-01-12T09:18:03.095700Z

(except that both won't work if you call the script from another directory ๐Ÿ˜… )

borkdude 2021-01-12T09:32:32.096700Z

@mmz unless you use absolute paths, like:

(require '[<http://clojure.java.io|clojure.java.io> :as io])
(load-file (io/file (.getParent (io/file *file*)) "dep.clj"))

2021-01-12T09:38:38.097800Z

Awesome! Best solution! ๐Ÿ‘:skin-tone-3: Thanks!

2021-01-12T15:30:06.099700Z

Think I finally found a rare bb bug ๐Ÿ˜…

(loop []
  (do   
    1
    (recur)
    2))
In clojure this does
Syntax error (UnsupportedOperationException) compiling recur at (form-init7929880134577873038.clj:4:5).
Can only recur from tail position
In babashka it returns 2 ๐Ÿ™‚

borkdude 2021-01-12T15:35:53.100100Z

yeah, babashka doesn't restrict recur to occur in tail position :P

2021-01-12T15:36:09.100300Z

Ah ok maybe a feature then

borkdude 2021-01-12T15:37:04.101100Z

it should probably throw or something, but it's just ignored

2021-01-12T15:37:38.101500Z

I accidentally had an extra item in tail position and I was getting weird results

2021-01-12T16:03:54.103800Z

You mean the recur is ignored, right?

(loop []
    (println "hi")
    (recur)
    2)
hi
2
Not really what I would expect. Shall I create a bug report with Sci?

borkdude 2021-01-12T16:04:05.104Z

yeah, would be good

๐Ÿ‘ 1
2021-01-12T16:23:28.105600Z

Done https://github.com/borkdude/sci/issues/498

pez 2021-01-12T18:07:21.107300Z

Can I have a babashka script require some utils from a separate module? I can make it work in the repl, but whe run as a script the util ns isnโ€™t found.

borkdude 2021-01-12T18:15:42.107700Z

@pez Scroll back the to the first post of today by @mmz

borkdude 2021-01-12T21:36:51.107800Z

Does that help?

pez 2021-01-12T21:37:36.108Z

It certainly looks like the same question. Will try it now.

borkdude 2021-01-12T21:38:49.108200Z

tl;dr; use (babashka.classpath/add-classpath ...) or load-file + *file* if you want absolute paths

pez 2021-01-12T21:49:49.108400Z

#!/usr/bin/env -S bb -cp ./script
Sort of works in my setting, but maybe I will want use absolute paths insteadโ€ฆ

borkdude 2021-01-12T21:53:05.108600Z

-S does this allow args in linux?

borkdude 2021-01-12T21:54:14.108800Z

for the longest time I thought env didn't take args on linux!

pez 2021-01-12T21:54:31.109Z

Not sure how portable it is.

borkdude 2021-01-12T21:55:18.109200Z

I just looked it up on my linux vps, appears to work!

๐Ÿค˜ 1
pez 2021-01-12T21:59:07.109400Z

The load-file way works when I run it as a script and if I evaluate the contents of the file in the repl, but it blows up when using the nrepl load-file op.

pez 2021-01-12T22:15:29.109700Z

nreplโ€™s load-file doesnโ€™t want to read the shabang either of course, but then I can manually load my helper module first and the main module after that and things are dandy.

borkdude 2021-01-12T22:20:41.109900Z

@pez why put something in a shebang at all? you can do this all in the script itself

borkdude 2021-01-12T22:21:03.110100Z

(require '[babashka.classpath :as cp])
(cp/add-classpath "script")

borkdude 2021-01-12T22:22:42.110300Z

and then (require 'script.foo)

borkdude 2021-01-12T22:22:58.110500Z

or (load-file "script/foo.clj")

pez 2021-01-12T22:26:35.110700Z

I just prefer (:require [script.foo :refer [bar]]) ยฏ\(ใƒ„)/ยฏ

pez 2021-01-12T22:27:33.110900Z

In the ns form.

borkdude 2021-01-12T22:32:41.111100Z

I am considering a .babashka/config.edn for projects where you can set the project classpath for example.

borkdude 2021-01-12T22:33:42.111300Z

But it is pretty normal in scripts to have multiple require forms, for setting the classpath, adding clojure deps (via babashka.deps), loading pods, ...

borkdude 2021-01-12T22:34:39.111800Z

Maybe there should be a .babashka/setup.clj where these side effects can occur

borkdude 2021-01-12T22:34:47.112Z

instead of a config file

pez 2021-01-12T22:41:27.112200Z

the Boot way ๐Ÿ˜ƒ

pez 2021-01-12T22:43:57.112400Z

I have too little experience with it to know which one is best. But it would be nice with some way to configure it, keeping the script less concerned with that stuff.

pez 2021-01-12T22:45:19.112600Z

It would also give the nrepl server a chance to read the :require stuff in the ns form in an informed way, right?

borkdude 2021-01-12T22:47:59.112800Z

The feedback I got a lot with the config file idea was that many people just use babashka for single scripts, so they would like to have an API for this, instead of an extra config file. But we could make an entry-point function which does this for you:

(defn -setup [..] ...)
which you can "hide" at the bottom of your script, or something, or just below the ns form. https://github.com/babashka/babashka/issues/680 Not sure about nREPL. If you use the babashka nrepl, then yes, but probably not on the JVM

borkdude 2021-01-12T22:50:42.113200Z

On the JVM you could make a condition at the bottom which executes the script, but then it should probably go before the ns form

borkdude 2021-01-12T22:51:02.113400Z

hmm, this issue is labeled "hammock" for a reason

pez 2021-01-12T22:54:29.113600Z

Haha, yeah. Iโ€™m currently using the babashka nrepl. I think Iโ€™ll fix clojure-lsp so that it helps with the script too. (Seems like it is just confused by the shebang.)

borkdude 2021-01-12T22:57:17.113800Z

Meanwhile I was trying this:

/usr/bin/env -S clojure -Sdeps '{:deps {:medley/medley {:mvn/version "1.3.0"}}}'

(println *command-line-args*)

borkdude 2021-01-12T22:57:22.114Z

maybe this is why the #_ + exec trick is needed

pez 2021-01-12T23:09:18.114300Z

I get

Error building classpath. class clojure.lang.Symbol cannot be cast to class clojure.lang.Keyword (clojure.lang.Symbol and clojure.lang.Keyword are in unnamed module of loader 'app')
Even from just:
clojure -Sdeps '{:deps {:medley/medley {:mvn/version "1.3.0"}}}'

borkdude 2021-01-12T23:10:45.114500Z

yeah sorry, the dep name should be a symbol

borkdude 2021-01-12T23:11:06.114700Z

but all I get is a REPL when using this approach and the code itself isn't executed in the file