Fork me on GitHub
#babashka
<
2023-09-29
>
vemv05:09:22

Quick check, is this the intended behavior for $HOME or an otherwise empty / non-bb-specific dir?

~ $ bb
Babashka v1.3.185 REPL.
Use :repl/quit or :repl/exit to quit the REPL.
Clojure rocks, Bash reaches.

user=> (System/getProperty "java.class.path")
""
(It's not causing big trouble but it's the first time I see an empty classpath)

lispyclouds06:09:09

That sounds about right. bb looks at https://github.com/babashka/babashka/blob/master/src/babashka/impl/classpath.clj#L80 places for the classpath and defaults to empty. What was your expectation?

borkdude07:09:53

No it sounds wrong, should be nil

lispyclouds07:09:39

i guess that would also work with nil

borkdude07:09:09

As long as it is not adding cwd to the classpath

lispyclouds07:09:36

ive always used babashka.classpath/get-classpath for this which gave nil, so not sure

borkdude07:09:49

Ok for a minute I thought I introduced a regressed in the new release but all good then

borkdude07:09:27

Don’t know why it would be an empty string if it wasn’t set yet though, I would expect nil

lispyclouds07:09:58

i tried looking for it, not sure where could it be

lispyclouds07:09:39

right, native-image/SubstrateVM seems to have it default to ""

lispyclouds07:09:20

native compile:

System.out.println("'%s' is the classpath".formatted(System.getProperty("java.class.path")));

lispyclouds07:09:53

thats whats probably happening in bb

lispyclouds07:09:35

public class Foo {
    public static void main(String... args) {
        System.out.println(System.getProperty("java.class.path").length()); // => 0
    }
}

lispyclouds07:09:18

System.getProperty("this.doesnt.exist")gives null

lispyclouds07:09:20

do we need the new SCI feature to make this return nil too? 😛 that would probably a breaking change

borkdude07:09:48

We can just set it to nil manually at startup but if it isn’t causing any bugs I would just let it be

borkdude07:09:19

Hmm might be interesting to actually use the new SCI feature for this to intercept the call but maybe wait a bit

borkdude09:09:02

jshell> System.getProperty("java.class.path")
$1 ==> "."
Apparently they can't live with a non-classpath

vemv11:09:51

. sounds reasonable since a file under $PWD is reasonable to be considered to be on the classpath, if nothing else was specified (expanding . to an absolute file name would probably be nicer to clients) However, I'm not experiencing a problem, I just assessed cider <-> bb integration (fixing a couple things while I was there) and wanted to make sure there are no weird corners

borkdude11:09:25

I have considered adding the PWD as the default classpath if nothing else was specified but so far I haven't made that decision yet. https://github.com/babashka/babashka/issues/1555

lispyclouds11:09:37

the default PWD seems to be specific to Java? Clojure, Kotlin, Scala all say different things

borkdude11:09:39

whatever GraalVM has set as a default, this does not affect how bb really works, since the system property is a mere reflection of the reality inside bb, not the source of truth

1
mattias14:09:49

I have a clojure (JVM) process which starts a Chromium process through Playwright. I also want to create a babashka task that runs this clojure process, so that I can potentially react to log messages in the JVM process. The problem is, if I shut down the babashka process with CTRL+C, the JVM process gets terminated but there is some Error: write EPIPE probably from Chromium (and next timke Chromium starts, it says it wasn't shut down correctly). This does not happen if I run the JVM process manually from bash. So I'm wondering if the babashka shell and babashka.process/process functions pass the correct termination signals to the JVM, or why is this happening? I've tried these bb tasks, which behave similarly:

runl1 (shell {:extra-env {"XTDB_ENABLE_BYTEUTILS_SHA1" true}}
               "clojure -A:web -X uxa.backend/main")
  runl2 (-> (p/process ["clojure" "-A:web" "-X" "uxa.backend/main"]
                       {:extra-env {:XTDB_ENABLE_BYTEUTILS_SHA1 "true"}
                        :inherit true
                        :shutdown p/destroy-tree})
            (p/check))

borkdude14:09:09

this won't solve your issue but for consistency: add the map as the first argument to process and the other arguments can be spliced as just string after that

borkdude14:09:27

the code looks good to me, not sure what happens

borkdude14:09:39

you could wrap this in an extra bash -c '...' to see if that solves the issue

👀 1
borkdude14:09:12

what you are doing with process is pretty similar to shell btw, exactly the same even I think

borkdude14:09:18

do you mean: when you quit bb, it should send SIGKILL or SIGINT to the running processes?

mattias14:09:28

i assume it should send SIGINT?

borkdude14:09:06

you could try this manually by adding a Shutdown hook which sends SIGINT to those processes... I'm not sure if the JVM / GraalVM does that by default

mattias14:09:54

ok, thanks, i'll try to figure out how to do that. btw wrapping the commands in bash -c '...' did not solve it

borkdude14:09:11

(def proc (babashka.process/process {:inherit true} "yes"))

(.addShutdownHook (Runtime/getRuntime)
                  (Thread. ^java.lang.Runnable (fn [] (babashka.process/destroy proc))))

🙏 1
borkdude14:09:27

I noticed that when you don't add the shutdown hook and destroy the process, the process keeps running

borkdude14:09:41

very annoying with "yes" ;)

borkdude14:09:46

oh wait, but this is exactly the same as (def proc (babashka.process/process {:inherit true :shutdown babashka.process/destroy} "yes"))

borkdude14:09:09

and seems to work correctly with:

(def proc (babashka.process/process {:inherit true :shutdown babashka.process/destroy} "yes"))

(Thread/sleep 10000)

borkdude14:09:15

when I quit it prematurely

borkdude14:09:46

so perhaps destroy isn't the right thing to send to your process for some reason, luckily it's configurable

mattias14:09:00

hmm ok, that would make sense

borkdude14:09:00

you can view the process builder API here: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Process.html you can get the raw process using (:proc proc) and then try some Java interop. Not sure

borkdude14:09:22

you can also get the .pid

mattias14:09:25

though .destroy sounds like it would send SIGINT and destroyForcibly would send SIGTERM

borkdude14:09:59

right. I think babashka.process/destroy uses forcible

borkdude14:09:12

not sure, might wanna check the source, gotta go for a bit

mattias14:09:30

ok thanks, but btw it uses .destroy

borkdude14:09:57

try forcibly then

borkdude14:09:08

we could make this an option in bb.process's destroy function

mattias14:09:43

OK I think I know what's happening. I was using :shutdown p/destroy-tree , which was sending SIGINT (?) to both the JVM process and the Chromium process (duh, since it's destroy-tree). But the clean way for handling this was to send :shutdown p/destroy , which sends SIGINT to just the JVM which in turn has a chance to shut down the Chromium process cleanly. So babashka was working entirely as expected, my bad!

🎉 2
💡 1
mattias14:09:15

But thanks for the quick replies and all the amazing open source contributions! 🙌

❤️ 1
Richie14:09:20

Hey! I have this code that works with clj-http:

(defonce cookie-store
  (doto
      (clj-http.cookies/cookie-store)
      (as-> cookie-store
        (binding [clj-http.core/*cookie-store* cookie-store]
          (http/post ""
                     {:form-params {:username "user"
                                    :password "password"}
                      :headers {:referer ""}})))))

(comment (http/get ""
                   {:cookie-store cookie-store
                    :headers {:referer ""}}))
Can you help me understand how to do that with babashka.http-client? I found ->CookieHandler but I can't figure out how to use it. I haven't found any examples either. https://github.com/babashka/http-client/blob/dc8ae30a5f52f1e1546755a7ec9984f25268c8c5/src/babashka/http_client.clj#L46-L54 Thanks!

Richie15:09:41

Although, this does work fine. I'm happy.

(def cookie (-> (http/post ""
                           {:form-params {:username "user"
                                          :password "password"}
                            :headers     {:referer ""}})
                :headers
                (update-keys csk/->kebab-case-keyword)
                :set-cookie))

(http/get ""
          {:headers {:referer ""
                     :cookie cookie}})

borkdude16:09:32

@UPD88PGNT did you find your answer?

borkdude16:09:59

oh cookie store, I get it

borkdude16:09:11

let me check how that works again

borkdude16:09:17

if you will then re-use the same client over and over, it will manage the cookies for you

borkdude16:09:39

Note that this is a client option, not a request option, so construct a client first

borkdude16:09:58

hope that helps

borkdude16:09:10

if you want to add anything to do the docs that you found missing, PR welcome