babashka

Filipe Silva 2025-08-29T12:16:07.720939Z

Is there a way to replace/patch/alter a single dependency namespace? I'm doing a http-kit server that's meant to run in both bb and clj, but keep running into errors when loading ring.util.response , which is a transitive dep of a lot of ring middleware.

----- Error --------------------------------------------------------------------
Type:     clojure.lang.ExceptionInfo
Message:  Unable to resolve classname: java.net.JarURLConnection
Data:     {:type :sci/error, :line 277, :column 1, :file "ring/util/response.clj", :phase "analysis"}
Location: ring/util/response.clj:278:20
Phase:    analysis

----- Context ------------------------------------------------------------------
274:     path
275:     (str path "/")))
276:
277: (defn- jar-directory? [^java.net.JarURLConnection conn]
278:   (let [jar-file   (.getJarFile conn)
                        ^--- Unable to resolve classname: java.net.JarURLConnection
279:         entry-name (.getEntryName conn)
280:         dir-entry  (.getEntry jar-file (add-ending-slash entry-name))]
281:     (and dir-entry (.isDirectory dir-entry))))
282:
283: (defn- connection-content-length [^java.net.URLConnection conn]

----- Stack trace --------------------------------------------------------------
ring.util.response/let   - ring/util/response.clj:278:20
ring.util.response       - ring/util/response.clj:278:3
clojure.core/let         - <built-in>
ring.util.response/fn    - ring/util/response.clj:278:3
clojure.core/fn          - <built-in>
... (run with --debug to see elided elements)
ring.util.response       - ring/util/response.clj:277:1
ring.util.response       - ring/util/response.clj:277:1
ring.middleware.resource - ring/middleware/resource.clj:3:3
invoker                  - /Users/filipesilva/repos/personal/invoker/src/invoker.clj:3:3
user                     - <expr>:1:10
This is similar to https://clojurians.slack.com/archives/CLX41ASCS/p1682919417008599

Filipe Silva 2025-08-30T17:26:26.298629Z

will that replace my global bb install via homebrew or?

Filipe Silva 2025-08-30T17:27:57.773069Z

ah no I see that it got installed to /tmp/bb, nice

Filipe Silva 2025-08-30T17:30:59.381099Z

I can confirm that wrap-resource works now in my original usage (serving files on bb using http-kit)!

Filipe Silva 2025-08-30T17:31:14.029709Z

filipesilva@m4 ~/r/p/invoker (master)> curl localhost/file.txt
foo

borkdude 2025-08-30T17:32:06.018919Z

nice!

Filipe Silva 2025-08-30T17:33:09.628619Z

thank you for taking the time to fix this 🙏

👍 1
Filipe Silva 2025-09-15T09:08:27.154189Z

heya, sorry to bother you again, but about clojure.lang.Ref... there's a couple of places in clojure-plus that try to use it, like this in clojure+.test

(defn- inc-report-counter [name]
  (condp instance? test/*report-counters*
    clojure.lang.Ref
    (dosync (commute test/*report-counters* update name (fnil inc 0)))
as far as I can tell it's kinda there in bb, but can't be resolved?
user=> (require '[clojure.test :as test])
nil
user=> (test/deftest foo (println (type test/*report-counters*)))
#'user/foo
user=> (test/run-tests)

Testing user
clojure.lang.Ref

Ran 1 tests containing 0 assertions.
0 failures, 0 errors.
{:test 1, :pass 0, :fail 0, :error 0, :type :summary}
user=> clojure.lang.Ref
Could not resolve symbol: clojure.lang.Ref [at <repl>:7:-16]
do you have any suggestions on what to do in this case? I could check the str instead of using instance?
user=> (test/deftest foo (println (= "class clojure.lang.Ref" (str (type test/*report-counters*)))))
#'user/foo
user=> (test/run-tests)

Testing user
true

Ran 1 tests containing 0 assertions.
0 failures, 0 errors.
{:test 1, :pass 0, :fail 0, :error 0, :type :summary}
user=>

borkdude 2025-09-15T09:15:37.266079Z

yes, I can add it. shall we use a different thread so we don't bother niki with all the details? let's take it one by one. please make a github issue

Filipe Silva 2025-09-15T09:16:10.795199Z

sgtm, thank you

borkdude 2025-09-15T09:17:11.895159Z

let me just add clojure.lang.Ref right now, no need for a gh issue

🔥 1
Filipe Silva 2025-09-14T15:49:25.640679Z

@tonsky tried adding babashka support to clj-reload here https://github.com/tonsky/clj-reload/pull/25, gonna look at all the clojure+ stuff now

borkdude 2025-09-14T16:24:56.125089Z

@filipematossilva I already have some WIP here for clj-reload as well: https://github.com/borkdude/clj-reload but I'm still working on SCI improvements to retain types defined with deftype and defclass even after you remove the namespaces. You will see that not working like JVM Clojure when you run the tests in babashka

borkdude 2025-09-14T16:26:39.653179Z

more notes here: https://github.com/babashka/babashka/issues/1839

Filipe Silva 2025-09-14T16:31:59.550959Z

oh shoot, I think you linked me that already but I completely forgot

Filipe Silva 2025-09-14T16:32:24.220869Z

well I needed a working version of clj-reload anyway to run the clojure+ tests so it wasn't wasted time

borkdude 2025-09-14T16:33:03.665959Z

with that minimal change, at least the code runs. but it just doesn't work fully for the defclass/deftype stuff. so maybe a good start

Filipe Silva 2025-09-14T17:28:20.151849Z

Removed stuff from clojure+ until I could get the remaining tests passing in a bb env, it looks a bit like this: • hashp and error install need .doReset , which looks like it could be replaced with an atom anyway • print install needed .addMethod on MultiFn • print has lots of java imports that don't work, and error tests also rely on print readers • hashp, print, and error tests are all down • then it's a bunch of smaller stuff that looks like it can be worked around • there's a couple of macros around clojure version support that look like they could be used for babashka support/not support If you're curious what it looks like, https://github.com/filipesilva/clojure-plus/commit/82d5b69bb8607e1741067fdd39ac25b71cbec00f

borkdude 2025-09-14T18:09:48.740239Z

> hashp and error install need .doReset , which looks like it could be replaced with an atom anyway this is about vars. you can use alter-var-root instead.

Filipe Silva 2025-09-14T18:32:45.385999Z

I never quite understood why some codebases prefer to store state in vars and alter them, is it just preference or are some cases where the atom won't work?

borkdude 2025-09-14T18:51:04.001969Z

I don't know but alter-var-root does what you want if you want to stay close to the original

👍 1
borkdude 2025-09-04T14:57:38.339119Z

@filipematossilva I decided to just add everything to bb that's needed to run clojure+.hashp unmodified. The only thing that could be improved now is the line number stuff. But you can already run it with the newest bb I believe

Filipe Silva 2025-09-04T15:06:51.347179Z

awesome!

Filipe Silva 2025-09-04T15:06:54.019539Z

let me try

Filipe Silva 2025-09-04T15:07:25.330339Z

filipesilva@m4 ~>  bb --version
babashka v1.12.208
filipesilva@m4 ~> rlwrap bb
Babashka v1.12.208 REPL.
Use :repl/quit or :repl/exit to quit the REPL.
Clojure rocks, Bash reaches.

user=> (deps/add-deps '{:deps {io.github.tonsky/clojure-plus {:mvn/version "1.6.3"}}})
nil
user=> (require 'clojure+.hashp)
nil
user=> (clojure+.hashp/install!)
java.lang.IllegalArgumentException: No matching method doReset found taking 1 args for class sci.lang.Var [at clojure+/hashp.clj:123:4]
user=>
hm I think there's still something wrong... I guess it's a different type of problem though, because it's on the install fn

borkdude 2025-09-04T15:07:47.604029Z

oh yes, you're right.... I forgot about .doReset. This can be changed in alter-var-root + constantly

borkdude 2025-09-04T15:08:15.462379Z

(I sound like an LLM now...)

Filipe Silva 2025-09-04T15:08:36.594969Z

you're absolutely right! XD

Niki 2025-09-04T15:25:12.678069Z

Guys, if at any point you need anything changed in clojure+ itself, just open a PR. Will be happy to help

❤️ 2
Filipe Silva 2025-08-31T12:03:39.105079Z

@tonsky fyi this is the thread related to https://github.com/babashka/babashka/issues/1853, I tagged you on the issue with the results of trying to install the rest of the clojure+ ns's

borkdude 2025-08-31T12:06:21.944689Z

I'm already talking with @tonsky on this. I'll send a PR based on the code in the issue. But one thing that wasn't working that well is showing the location of the #p in the output, was trying to improve on that still

borkdude 2025-08-31T12:06:47.310209Z

I could also send a PR without the improvements first so at least it's working on bb

Filipe Silva 2025-08-31T12:10:56.157509Z

ah sorry, didn't mean to get in the way, it's just that I was trying to install all the others and thought I should put down what happens in case the whole thing was a bit of a fools errand

borkdude 2025-08-31T12:13:42.511359Z

thanks! it's appreciated

borkdude 2025-08-31T12:14:51.012219Z

I added Compiler/demunge to bb. I'll make a PR to remove TaggedLiteral interop in favor of tagged-literal in core. These changes should at least make things work

Filipe Silva 2025-08-31T12:17:22.167659Z

I'm in no rush myself really... I just happened to be trying it out, and since there were no issue reports on it I thought I'd make some, then eventually if other people tried there was some help and context

borkdude 2025-08-31T12:24:11.438969Z

thanks :) I might have done a PR on weavejester's hashp at some point maybe

borkdude 2025-08-31T12:25:10.532559Z

(no I didn't)

Filipe Silva 2025-08-31T12:26:56.100829Z

you had https://github.com/weavejester/hashp/issues/21, but I think it still suffers from the location issue

Filipe Silva 2025-08-31T12:28:49.968659Z

it shows

filipesilva@m4 ~/r/p/invoker (master) [SIGINT]> invoker http
#p[clojure.core/apply:667] req => {:args [],
 :async-channel #<org.httpkit.server.AsyncChannel@51c7a210 /[0:0:0:0:0:0:0:1]:80<->/[0:0:0:0:0:0:0:1]:54325>,
 :body #<org.httpkit.BytesInputStream@4d90c592 BytesInputStream[len=3]>,
 :character-encoding "utf8",
for
(defn http-invoke [{:as req, :keys [var args opts]}]
  (try
    #p req
...

borkdude 2025-08-31T12:30:59.649599Z

should I close that issue?

Filipe Silva 2025-08-31T12:33:16.840109Z

Your issue is about how the location isn't accurate, which is still true, so I'd say no. https://github.com/weavejester/hashp/pull/25 aimed to fix how it didn't work at all in clojure 1.12, but that's been fixed already.

Filipe Silva 2025-08-29T12:18:45.284859Z

I don't really know if the middleware I'm trying to use right now (`ring.middleware.resource`) would work at all if I managed to get past this particular error... but a couple of weeks ago I hit the same issue with another middleware, and at any rate ring.util.responses has lots of useful helpers that are ubiquitous in ring apps, like

(defn not-found
  "Returns a 404 'not found' response."
  {:added "1.1"}
  [body]
  {:status  404
   :headers {}
   :body    body})

(defn response
  "Returns a skeletal Ring response with the given body, status of 200, and no
  headers."
  [body]
  {:status  200
   :headers {}
   :body    body})

borkdude 2025-08-29T12:19:46.133959Z

btw java.net.JarURLConnection was added in 1.12.206 (2025-07-16)

borkdude 2025-08-29T12:20:35.901379Z

if you can upgrade, we can see if there's other things to add/fix

Filipe Silva 2025-08-29T12:21:02.636819Z

borkdude you are a gem ❤️

Filipe Silva 2025-08-29T13:30:25.688999Z

Sorry for the delay confirming it works, it seems to have a problem and I was debugging it. Well I can confirm the require goes through, but ring.middleware.resource doesn't work. It seems to be related to https://github.com/ring-clojure/ring/blob/8fcd3b6594fc66c156e7c4e5f66a55c6acf952f6/ring-core/src/ring/util/response.clj#L309-L312, that gets called in the fns below it. Specifically this piece of code behaves differently between bb and clj:

(-> (.getContextClassLoader (Thread/currentThread))
      (.getResources "public")
      (enumeration-seq))
here's a repro:
mkdir repro
cd repro
echo '{:paths ["src" "resources"]}' > bb.edn
cp bb.edn deps.edn
mkdir -p resources/public
touch resources/public/file.txt
then in clj we see the folder
filipesilva@m4 ~/r/s/bb-resources> clj -M -e '(-> (.getContextClassLoader (Thread/currentThread)) (.getResources "public") (enumeration-seq))'
(#object[java.net.URL 0x772485dd "file:/Users/filipesilva/repos/sandbox/bb-resources/resources/public"])
but in bb we do not
filipesilva@m4 ~/r/s/bb-resources> bb -e '(-> (.getContextClassLoader (Thread/currentThread)) (.getResources "public") (enumeration-seq))'

Filipe Silva 2025-08-29T13:31:11.177339Z

maybe it's just a matter of using the right class loader in the middleware opts

borkdude 2025-08-29T13:31:15.686169Z

ok, nice repro. can you file an issue for this, then I'll have a look

borkdude 2025-08-29T13:31:44.371049Z

do you actually have the resources folder on your classpath in bb?

borkdude 2025-08-29T13:31:49.224029Z

in bb.edn

borkdude 2025-08-29T13:32:10.743269Z

oh yes, you have sorry

Filipe Silva 2025-08-29T13:32:11.981399Z

uhm I assume echo '{:paths ["src" "resources"]}' > bb.edn did that, maybe I am wrong

Filipe Silva 2025-08-29T13:32:32.573249Z

I'll print the file in the repo to demonstrate that

borkdude 2025-08-29T13:32:44.200899Z

thank you

Filipe Silva 2025-08-29T13:34:12.230229Z

yeap there

Filipe Silva 2025-08-29T13:34:13.649109Z

filipesilva@m4 ~/r/s/bb-resources> clj -M -e '( "public/file.txt")'
#object[java.net.URL 0x44e3760b "file:/Users/filipesilva/repos/sandbox/bb-resources/resources/public/file.txt"]
filipesilva@m4 ~/r/s/bb-resources> bb -e '( "public/file.txt")'
#object[java.net.URL 0x72531f93 "file:/Users/filipesilva/repos/sandbox/bb-resources/resources/public/file.txt"]

Filipe Silva 2025-08-29T13:36:04.354919Z

lol https://github.com/babashka/babashka/issues/1851 and https://github.com/babashka/babashka/issues/1839 are things I wanted to test too 😄

borkdude 2025-08-29T13:36:52.294969Z

nice, they are still active to do :)

borkdude 2025-08-29T13:37:01.736299Z

feel free to bump those issues with a thumbs up

👍 1
borkdude 2025-08-29T13:37:41.020779Z

clj-reload is the first thing I want to fix. it basically already works except not with deftype/defrecord stuff yet

Filipe Silva 2025-08-29T13:43:16.005709Z

out of curiosity have you tried https://github.com/tonsky/clojure-plus?tab=readme-ov-file#clojurehashp ? I think atm it doesn't work

filipesilva@m4 ~/r/s/bb-resources [SIGINT]> rlwrap bb
Babashka v1.12.207 REPL.
Use :repl/quit or :repl/exit to quit the REPL.
Clojure rocks, Bash reaches.

user=> (require '[babashka.deps :as deps])
nil
user=> (deps/add-deps '{:deps {io.github.tonsky/clojure-plus {:mvn/version "1.6.3"}}})
Downloading: io/github/tonsky/clojure-plus/1.6.3/clojure-plus-1.6.3.pom from clojars
Downloading: io/github/tonsky/clojure-plus/1.6.3/clojure-plus-1.6.3.jar from clojars
nil
user=> (require 'clojure+.hashp)
java.lang.Exception: Unable to resolve classname: clojure.lang.TaggedLiteral [at clojure+/hashp.clj:7:3]

Filipe Silva 2025-08-29T13:44:43.666739Z

the original hashp seems fine though

user=> (deps/add-deps '{:deps {dev.weavejester/hashp {:mvn/version "0.4.0"}}})
nil
user=> (require 'hashp.preload)
nil
user=> #p "hello"
#p[babashka.impl.repl/repl:84] "hello"
"hello"

borkdude 2025-08-29T13:45:32.398849Z

the original works fine. I haven't tried clojure+

borkdude 2025-08-29T13:45:47.760469Z

add an issue for it, I can take a look

👍 1
Filipe Silva 2025-08-29T13:53:31.584079Z

issue for wrap-resource https://github.com/babashka/babashka/issues/1852

Filipe Silva 2025-08-29T14:00:12.129779Z

issue for clojure+.hashp https://github.com/babashka/babashka/issues/1853

borkdude 2025-08-29T14:00:39.129469Z

👍 I'll see what I can do

🙏 1
borkdude 2025-08-29T21:32:11.481389Z

@filipematossilva This issue is fixed on master. https://github.com/babashka/babashka/issues/1852 You can try it out with:

bash <(curl )  --dev-build --dir /tmp
when CI is finished. Should be in 10 minutes or so

borkdude 2025-08-29T20:34:36.526109Z

There's going to be a bb-and-clj-kondo-related talk at the #clojure-conj this year!

🎉 15