Fork me on GitHub
#babashka
<
2022-12-22
>
lucian30307:12:42

here's a strange message. i just installed clj and am trying to run a regular clojure program using clj which works fine locally. but it seems clojure now depends on babashka? i'm not using babashka, it's not installed, it's not referenced and yet it's trying to find it? even if i install it, i get the same error. it's beyond comprehension why it would be looking for babashka.process.Process or why that would have anything to do with clj. i wasn't sure if i should post this in this channel or the clojure channel.

clj -M screenshot.clj 
Starting ...
java.lang.IllegalArgumentException: Multiple methods in multimethod 'simple-dispatch' match dispatch value: class babashka.process.Process -> interface clojure.lang.IDeref and interface clojure.lang.IPersistentMap, and neither is preferred
at clojure.lang.MultiFn.findAndCacheBestMethod(MultiFn.java:179)
at clojure.lang.MultiFn.getMethod(MultiFn.java:150)
at clojure.lang.MultiFn.getFn(MultiFn.java:154)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
_base.clj:194)jure.pprint$write_out.invokeStatic(pprint
at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
at clojure.pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
at clojure.pprint$pprint_map.invoke(dispatch.clj:106)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
ke(dispatch.clj:113)print$pprint_map$fn__11151.invo
at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
at clojure.pprint$pprint_map.invoke(dispatch.clj:106)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
at clojure.pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
6)      at clojure.pprint$pprint_map.invoke(dispatch.clj:10
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
at clojure.pprint$pprint_vector$fn__11136.invoke(dispatch.clj:95)
at clojure.pprint$pprint_vector.invokeStatic(dispatch.clj:94)
at clojure.pprint$pprint_vector.invoke(dispatch.clj:92)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
.pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
at clojure.pprint$pprint_map.invoke(dispatch.clj:106)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
at clojure.pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
pprint_map.invoke(dispatch.clj:106)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
at clojure.pprint$pprint$fn__10392.invoke(pprint_base.clj:249)
at clojure.pprint$pprint.invokeStatic(pprint_base.clj:248)
at clojure.pprint$pprint.invoke(pprint_base.clj:241)
at clojure.pprint$pprint.invokeStatic(pprint_base.clj:245)
at clojure.pprint$pprint.invoke(pprint_base.clj:241)
at clojure.lang.Var.invoke(Var.java:384)
port_error$fn__9280$fn__9281.invoke(main.clj:603)
at clojure.main$report_error$fn__9280.invoke(main.clj:602)
at clojure.main$report_error.invokeStatic(main.clj:601)
at clojure.main$main.invokeStatic(main.clj:666)
at clojure.main$main.doInvoke(main.clj:616)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.main.main(main.java:40)
deps.edn:
{:paths ["."]
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}
        etaoin/etaoin       {:mvn/version "1.0.38"}}}

borkdude07:12:52

Please don’t post long traces in the main channel but use a gist or thread

borkdude07:12:47

The solution is in the README of etaoin: the babashka process library is used in etaoin and you can enable its pprint method following that

borkdude10:12:27

I think this shouldn't happen with the newest etaoin at all anynmore since babashka.process/pprint is already required there

pez10:12:01

@U053KNT7C. The original message got a bit long for the main channel. We deleted it and I'm posting it back here now: > here's a strange message. i just installed clj and am trying to run a regular clojure program using clj which works fine locally. but it seems clojure now depends on babashka? i'm not using babashka, it's not installed, it's not referenced and yet it's trying to find it? even if i install it, i get the same error. it's beyond comprehension why it would be looking for babashka.process.Process or why that would have anything to do with clj. i wasn't sure if i should post this in this channel or the clojure channel. >

clj -M screenshot.clj 
> Starting ...
> java.lang.IllegalArgumentException: Multiple methods in multimethod 'simple-dispatch' match dispatch value: class babashka.process.Process -> interface clojure.lang.IDeref and interface clojure.lang.IPersistentMap, and neither is preferred
> at clojure.lang.MultiFn.findAndCacheBestMethod(MultiFn.java:179)
> at clojure.lang.MultiFn.getMethod(MultiFn.java:150)
> at clojure.lang.MultiFn.getFn(MultiFn.java:154)
> at clojure.lang.MultiFn.invoke(MultiFn.java:229)
> _base.clj:194)jure.pprint$write_out.invokeStatic(pprint
> at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
> at clojure.pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
> at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
> at clojure.pprint$pprint_map.invoke(dispatch.clj:106)
> at clojure.lang.MultiFn.invoke(MultiFn.java:229)
> at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
> at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
> ke(dispatch.clj:113)print$pprint_map$fn__11151.invo
> at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
> at clojure.pprint$pprint_map.invoke(dispatch.clj:106)
> at clojure.lang.MultiFn.invoke(MultiFn.java:229)
> at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
> at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
> at clojure.pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
> at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
> 6)      at clojure.pprint$pprint_map.invoke(dispatch.clj:10
> at clojure.lang.MultiFn.invoke(MultiFn.java:229)
> at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
> at clojure.pprint$pprint_vector$fn__11136.invoke(dispatch.clj:95)
> at clojure.pprint$pprint_vector.invokeStatic(dispatch.clj:94)
> at clojure.pprint$pprint_vector.invoke(dispatch.clj:92)
> at clojure.lang.MultiFn.invoke(MultiFn.java:229)
> at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
> at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
> .pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
> at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
> at clojure.pprint$pprint_map.invoke(dispatch.clj:106)
> at clojure.lang.MultiFn.invoke(MultiFn.java:229)
> at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
> at clojure.pprint$pprint_map$fn__11151$fn__11153.invoke(dispatch.clj:113)
> at clojure.pprint$pprint_map$fn__11151.invoke(dispatch.clj:113)
> at clojure.pprint$pprint_map.invokeStatic(dispatch.clj:112)
> pprint_map.invoke(dispatch.clj:106)
> at clojure.lang.MultiFn.invoke(MultiFn.java:229)
> at clojure.pprint$write_out.invokeStatic(pprint_base.clj:194)
> at clojure.pprint$pprint$fn__10392.invoke(pprint_base.clj:249)
> at clojure.pprint$pprint.invokeStatic(pprint_base.clj:248)
> at clojure.pprint$pprint.invoke(pprint_base.clj:241)
> at clojure.pprint$pprint.invokeStatic(pprint_base.clj:245)
> at clojure.pprint$pprint.invoke(pprint_base.clj:241)
> at clojure.lang.Var.invoke(Var.java:384)
> port_error$fn__9280$fn__9281.invoke(main.clj:603)
> at clojure.main$report_error$fn__9280.invoke(main.clj:602)
> at clojure.main$report_error.invokeStatic(main.clj:601)
> at clojure.main$main.invokeStatic(main.clj:666)
> at clojure.main$main.doInvoke(main.clj:616)
> at clojure.lang.RestFn.applyTo(RestFn.java:137)
> at clojure.lang.Var.applyTo(Var.java:705)
> at clojure.main.main(main.java:40)
> > deps.edn: >
{:paths ["."]
>  :deps {org.clojure/clojure {:mvn/version "1.11.1"}
>         etaoin/etaoin       {:mvn/version "1.0.38"}}}
>

lread14:12:28

Yes, latest release of etaoin should address this, please let us know if you still have issues in #C7KDM0EKW

lucian30318:12:34

sorry, i didn't know about the traces. i'll use a snippet next time. thank u all for u'r responses

borkdude20:12:11

no problem. hope you found the solution to your problem?

borkdude10:12:22

Dear babashka friends! Please keep your questions coming, but I don't like messages that flood this channel with long stack traces. If you provide those, please use a snippet, gist or post them in a thread. In case of flooding, I will ask an admin to remove the message and move it to a thread in case the original poster doesn't respond within an hour. Thank you!

👍 8
1
1
jumar11:12:52

Sharing them as a snippet is also an alternative - at least I find snippets useful for longer stacktraces.

👍 1
Brandon Stubbs14:12:38

I wonder if the admins would want to create a Clojure slack management bot? This could do things like • detect if people are sending multiple messages in a row. If it’s the first time communicating with them, show them how to thread the message. If it’s the nth time, just a gentle threading reminder. • detect if messages are extremely long / contain a stacktrace and ask them to put the subject line of the question and the detail in the thread. etc. I am sure there is a lot of admin overhead that could be added into the bot to automate the moderation a bit

teodorlu16:12:47

Thanks for caring about the readers of this channel!

seancorfield17:12:46

@U015Y1A1N8Y I expect the Admins would welcome someone volunteering their time and effort to help with their moderation effort -- but don't appreciate people suggesting extra work for the Admin team (who are all volunteers themselves)... @U04V15CAJ Slack does not provide any way to "move [messages] to a thread" -- we can only delete messaes.

borkdude17:12:22

@U04V70XH6 I know, but what we did above is start the thread, delete the top message and repost it in the thread.

seancorfield17:12:56

Yeah, the only problem with that is the Admin then ends up in a thread they may not be interested in and the message's OP is lost (and then other people have a habit of @-ing the Admin about stuff in that thread). In the end, it just causes more work for us. I'll have a look at the permissions setup and see if we can provide a group of trusted folks as "channel owners" the ability to delete other people's messages as a way for those folks to better manage their own projects' channels...

seancorfield17:12:34

...Hmm, the only options are "Everyone" and "Workspace owners and Admins" so we'd have to expand the pool of Admins to make that possible. Do you want to become a general Admin of the Workspace, @U04V15CAJ? 🙂

borkdude19:12:20

> Yeah, the only problem with that is the Admin then ends up in a thread they may not be interested in You can unsubscribe from the thread afterwards :)

borkdude19:12:30

> Do you want to become a general Admin of the Workspace Sure :)

lispyclouds21:12:49

I’ve seen https://github.com/brunolemos/threadbot being used at places. Kinda annoying in the beginning but people catch on 😅

borkdude21:12:21

This sounds almost what I want, but it doesn't have the long stacktrace detection right? ;)

lispyclouds21:12:51

Yeah, that can be contributed I think!

lispyclouds21:12:38

The thing that it does already is more complicated than long Stacktrace detection I think.

Adam Helins12:12:16

Does Babashka have an equivalent to clojure -Sdescribe?

borkdude12:12:37

Yes: bb --describe 😂

borkdude12:12:18

not sure what you're after though

Adam Helins12:12:40

Haha, indeed, but something that would show intel like :config-dir etc. Context: I reached a CI situation where launching a BB task tries to create a /.clojure/.cpcache dir (and fails because it's not the right place).

borkdude12:12:13

try bb clojure -Sdescribe

Adam Helins12:12:23

Ah well, it seems it won't help:

$ bb clojure -Sdescribe
Picked up JAVA_TOOL_OPTIONS: -Duser.home=/var/lib/gitlab-runner

Error building classpath. Can't create directory: /.clojure/.cpcache

borkdude12:12:54

Hmm, -Sdescribe doesn't really need to build a classpath, I guess... what platform are you using?

borkdude12:12:00

as in, what os

Adam Helins12:12:23

This is on a Nix-based runner, I'm trying to figure it out with @U033F53LU0M who is our Ops angel

Adam Helins12:12:05

This looks really fishy doesn't it:

$ bb --version
Picked up JAVA_TOOL_OPTIONS: -Duser.home=/var/lib/gitlab-runner

Error building classpath. Can't create directory: /.clojure/.cpcache

borkdude12:12:27

Yes, I don't know where this is coming from ... maybe gitlibs?

borkdude12:12:57

Oh I see, this is coming from Clojure:

$ JAVA_TOOL_OPTIONS="-Duser.home=/tmp/dude" clj
Picked up JAVA_TOOL_OPTIONS: -Duser.home=/tmp/dude
Clojure 1.11.0

Adam Helins12:12:34

But why does it kick in with bb --version?

borkdude12:12:39

no from tools deps, I guess

borkdude12:12:13

because bb --version doesn't avoid loading deps from bb.edn I guess

borkdude12:12:43

you can do it like this for now: BABASHKA_CLASSPATH="" bb --version

borkdude12:12:34

To set the home dir for bb you can do it like this:

bb -Duser.home=/var/lib/gitlab-runner

Adam Helins12:12:38

Okay so it seems indeed that there is some trouble related to HOME, if you compare BB Vs Clojure CLI -Sdescribe: https://gist.github.com/helins/3d1fcb280e2c62df067cd8dac0fb8e3e

borkdude12:12:16

Yes, use the property I mentioned before your last reaction

borkdude12:12:24

deps.clj respects the user.home property

Adam Helins12:12:40

Great, seems like a fix, I think we can figure out the rest now! Thanks, very helpful as always 🙂

👍 1
borkdude12:12:59

but this part of the post doesn't hold anymore: > Babashka doesn’t support -Sdeps The latest version does now cc @U066U8JQJ

Wanja Hentze11:12:01

For the sake of posterity, the root cause of this discrepancy turns out to be https://bugs.openjdk.org/browse/JDK-8280357

Wanja Hentze11:12:53

tl;dr almost everything besides Java uses $HOME to find the home directory, but Java uses getpwuid. Since we run our gitlab-runners with systemd's DynamicUser setting, this causes the aforementioned discrepancy. We had worked around this discrepancy via the JAVA_TOOL_OPTIONS thing mentioned earlier, but that broke for some bb invocations. I think I may disable DynamicUser altogether and rework the isolation story for our CI runners.

🤯 1
Wanja Hentze11:12:54

They did fix this upstream in OpenJDK eventually: https://github.com/openjdk/jdk/pull/7534 but it will take forever until that makes it into an LTS release

annarcana22:12:38

Is there a way of having concurrent babashka.process processes? dialog has an option that creates a progress bar by watching stdin for integers, so you can do something like some-long-thing | dialog --gauge and it'll watch the stdin for integers as it runs, and use those to update the progress in the dialog. But I'm having trouble translating that behavior to babashka, because while you can capture the :out of a process and pass it to a second, it blocks until the first is done rather than updating as it runs.

annarcana22:12:51

Frex, this will work from the shell:

bb -e '(doseq [x (range 1 100)] (Thread/sleep 100) (println x))' | dialog --gauge "Testing" 0 0

borkdude22:12:10

@U13N2SPMZ Yes, this is possible. To do this, use process, not shell since shell is blocking

annarcana22:12:49

I have been but I think the order of dereferencing might be wrong? Lemme post some snippets, just a sec.

borkdude22:12:07

You launch dialog like this:

(process "dialog --gauge 'Testing' 0 0")
which returns a thing that has :in and :out . I assume you want to see the results immediately, so you provide :err :inherit , assuming that dialog writes to stderr for visualization:
(process {:err :inherit} "dialog --gauge 'Testing' 0 0")

borkdude22:12:32

yes, you deref too early

borkdude22:12:59

and so

(process {:err :inherit} "dialog --gauge 'Testing' 0 0")
returns a a map that has :in , a stream that you can write to

annarcana22:12:07

dialog displays to stdout, it uses stderr for return values

borkdude22:12:19

oh that's weird, but ok

borkdude22:12:37

let me try to make a small full example, brb

👍 1
annarcana22:12:03

No problem, probably should've posted a simpler example myself 😅

borkdude22:12:20

@U13N2SPMZ

(require '[babashka.process :refer [process]]
         '[ :as io])

(let [dialog (process {:out :inherit
                       :err :string} "dialog --gauge 'Testing' 0 100")]
  (with-open [in (io/writer (:in dialog))]
    (binding [*out* in]
      (doseq [i (range 1 101)]
        (println i)
        (Thread/sleep 10))
      (println "99")))
  (println (:err @dialog))
  nil)

👏 1
borkdude22:12:25

(made a small edit)

annarcana22:12:31

OK, that does work at least. The question is how can I generalize this such that someone can provide arbitrary processes. :thinking_face:

borkdude22:12:05

arbitrary processes?

borkdude22:12:48

time to cool down over here... I'll check back in tomorrow :)

annarcana22:12:09

I'm working on a library for working with dialog. So I've been trying to puzzle out how the API can work for stuff where the CLI version is "pipe thing to dialog"

annarcana22:12:02

So my initial thought was "pass :out from a process"