This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-12
Channels
- # announcements (4)
- # babashka (60)
- # beginners (3)
- # calva (15)
- # cherry (1)
- # clojars (9)
- # clojure (30)
- # clojure-denmark (5)
- # clojure-europe (23)
- # clojure-losangeles (1)
- # clojure-norway (8)
- # clojurescript (49)
- # core-async (3)
- # cursive (15)
- # datomic (4)
- # deps-new (1)
- # emacs (36)
- # figwheel-main (3)
- # fulcro (16)
- # girouette (2)
- # hyperfiddle (1)
- # introduce-yourself (3)
- # lambdaisland (6)
- # nrepl (23)
- # off-topic (7)
- # pedestal (10)
- # polylith (50)
- # practicalli (1)
- # releases (2)
- # sci (16)
- # shadow-cljs (27)
- # slack-help (3)
- # sql (17)
- # tools-deps (5)
I too often struggle figuring out how to pass args and options to babashka process, and I'm sure it's a "me" problem. I generally build up arguments into a vector and then use apply
to pass it to p/process
along with some options. Often there's some thread macro usage as well. For example:
;; *-args are vectors of command arguments
(-> (p/process some-cmd-args {:dir working-dir})
(p/process {:out :string, :dir working-dir} (str/join " " some-other-cmd-args))
(deref))
That took an emabarrassingly long time for me to make work, and I'm not happy with my use of str/join
to make the second command work. And the flipping of the options and command positions doesn't make sense to me either. I don't have a great conceptual model of what's going on here, and I'm sure that (a) I'm doing something wrong and (b) it's because I don't understand what's going on. How do others think about this? How do others approach it?@U0EHU1800 The official syntax is:
(process ?opts-map args+)
you don't have to str/join them, any number of strings works, the first string is tokenized automatically
How should I approach this if I want to have a vector of arguments? I don't like building up strings for shell commands, and I like to be able to build them up in incrementally. Using apply
to try to use varargs has been hard to do, too.
Just don't use the thread operator if that confuses things, maybe?
(let [p1 (apply p/process {:dir working-dir} some-cmd-args)
p2 (apply p/process p1 {:out :string, :dir working-dir} some-other-cmd-args)]
(deref p2))
Potentially, yeah. Now I'm wondering whether that first (p/process args opts)
is doing what I think it's doing. Though, hard for me to think otherwise as it wouldn't find the stuff on disk it needs if it weren't.
Yeah, that's what I'm saying. I definitely have (p/process args opts)
in my code right now.
strace -e execve
to see if the arguments are 'spread' across arguments to the invocation of the process
Interesting. @U01KUQRDMLG can you elaborate?
@U04V15CAJ Thanks for explaining why the two different spellings work.
I've been contemplating the single map argument version for a while. The varargs version is particularly handy with (apply p/process **command-line-args*
)*
And people were confused why p/shell
had a different argslists than p/process
so it all got normalized
(I've stared at the source of how options and arguments are handled, and boy, that's been hard for me to follow)
That normalization makes sense. I'll probably submit a PR with some more examples in the readme, if you don't mind.
❯ strace -f -e execve bb
user=> (require '[babashka.process :refer [process check sh pipeline pb]])
nil
user=> (process "echo test 123")
strace: Process 2309863 attached
[pid 2309863] execve("/usr/bin/echo", ["echo", "test", "123"], 0x7ffe51b74fe8 /* 42 vars */) = 0
I did strace -f -e execve bb
when i started bb and now i can see exactly how the args are passed to the subprocess
@U01KUQRDMLG Cool! Thanks! Same thing should work for JVM? (e.g., strace -f -e execve clj
)
strace is very very useful
user=> (proc/parse-args "ls -la")
{:prev nil, :cmd ["l" "s" " " "-" "l" "a"], :opts nil}
eh I mean:
user=> (proc/parse-args ["ls -la"])
{:prev nil, :cmd ["ls" "-la"], :opts nil}
Have you used strace with, say, CIDER? (I spend most of my time in an emacs buffer). Actually, I could use cider-connect instead of cider-jack-in. That'd be easy enough.
I have not, it should work fine, just use -o
to log to a file, -e
is the syscall filter, you can filter whatever you want
no problem 🙂
@U0EHU1800 So how about this?
(def ls-proc (proc/process {:cmd ["ls"]}))
(:out @(proc/process {:prev ls-proc :cmd ["wc" "-l"] :out :string}))
" 13\n"
The :prev
argument is the "previous process that is piped in" (could use a better name but this is what I have used internally)
The :cmd
vector are the process argumentsI like the :cmd
vector. (I could also see that being optionally a string to be tokenized or a vector because some people like the string form, but I personally would only use the vector form: I could also see deferring adding the string option until people clamor for it)
I do like the transparent behavior of threading to "pipe" processes. Would that still work?
yes:
user=> (-> ls-proc (proc/process {:cmd ["wc" "-l"] :out :string}) deref :out)
" 13\n"
I think people can use proc/tokenize
explicitly to tokenize a string into a vec of strings maybe
(Thanks for thinking about this, by the way. The discussion we had above is enough for me to be able to use process as it currently works)
and should we allow (proc/process {:cmd ["ls"]} "-la")
? (as in merge the both things? I think that's getting out of hand)
re: :prev
vs other names, I'd just be spit-balling. :in-proc
? Is there any term of art for this in terms of pipelining generally?
PR: https://github.com/babashka/process/pull/109 I'll finish it after dinner with some docs.
Actually I'll wait with merging, since clojure 1.12 will have something like process as well and it's very much inspired by bb process and has the same (recommended) calling convention. https://clojure.atlassian.net/browse/CLJ-2759 By having the same calling convention for both and just better docs should probably solve this.
I added some extra notes here: https://github.com/babashka/process#syntax Feel free to send a PR with additional improvements if you think it helps
Will do! (If you have any tuits—particularly of the round variety—I'd appreciate any you can pass my way 😛)
Hmm. Adding a new feature (locally -- I don't think there's a compelling case for inclusion upstream here), I can require
its namespace when running ./bb
(but not run it successfully yet; getting an ExceptionInInitializerError); trying to repro under a "real" JVM in the hopes of getting a more informative stack trace, though, java -jar ./target/babashka-1.3.177-SNAPSHOT-standalone.jar
is simply not finding the namespace when trying to import it.