Fork me on GitHub
#babashka
<
2023-06-05
>
pesterhazy11:06:54

When converting bash scripts, I'm finding this a common pattern

(let [date (str/trim-newline (:out (shell {:out :string} "date" "+%F")))])
Just think out loud, could this be something shorter?
(let [date (shell-capture "date" "+%F")])
sh (https://github.com/babashka/process/blob/master/API.md#babashka.process/sh) is subtly different

borkdude11:06:57

I think just writing your own util makes sense

pesterhazy11:06:08

yeah I guess

borkdude11:06:47

perhaps a helper function would make sense, but then you'd need to pass :out or :err etc and probably you would end up with pretty much the same as writing it manually

pesterhazy12:06:51

playing with the idea a little:

(defn shellc [input & args]
  (str/trim-newline (:out (apply shell (cond-> {:out :string}
                                         input
                                         (assoc :inp input))
                                 args))))

(println (shellc "whoami"))

;; now we can build a "pipeline" (although it doesn't use UNIX pipes)

(-> (shellc nil "cat" "/etc/fstab")
    (shellc "rev")
    (shellc "sed" "s/abc/def/"))

pesterhazy12:06:44

Gives you lightweight pipelines (which are sequential, in-memory, without streaming etc)

pesterhazy12:06:16

The nil in the first call is a wart in the api

borkdude12:06:24

I think this is almost what the new clojure 1.12 clojure.java.process/exec function is doing

borkdude12:06:32

although it might not strip the newline

pesterhazy12:06:21

Hm and it doesn't allow the use of thread-first to thread through a value

borkdude12:06:29

another way to put it: it returns stdout rather than anything else, so it saves you just writing :out ;)

pesterhazy12:06:42

maybe I want too much convenience 🙂

borkdude12:06:18

that's the thing right: people on the one hand ask for more decomplectedness, but on the other hand more convenience ;)

😅 2
📈 2
📉 2
pesterhazy12:06:04

sometimes you find a design where there's no trade-off – you get both simplicity and convenience

pesterhazy12:06:22

but (shellc nil "cat" "/etc/fstab") ain't it 🙂

borkdude12:06:08

btw, the one thing you didn't like was the automatic tokenization (which is for convenience). if you now pass (process {:cmd ["ls" "-la"]}) it doesn't do the tokenization on the :cmd thing

pesterhazy12:06:51

ahhh good to know

pesterhazy12:06:01

the process api is surprisingly hard to get right

pesterhazy12:06:07

Python's capture_output is also not super nice

borkdude12:06:33

one of the complicated things about it is that it's async and also because there's streams of things. in Node.js it also isn't super obvious

pesterhazy12:06:34

I prefer babashka.process by a big margin

pesterhazy12:06:34

yeah right, a ton of opt-in complexity • checking exit status • async vs blocking • streaming vs gimme-a-string-already • stderr handling

pesterhazy12:06:55

bash gets the "checking exit status" part horribly wrong

pesterhazy12:06:16

it's broken-ish both with and without set -e

borkdude12:06:29

similar to what Javascript did early on I think? just continue whatever's happening

borkdude12:06:22

One thing that also helps in Clojure is that analysis is performed on top level forms, so if you have an unresolved symbol, it throws and doesn't just report it on first usage of the function

borkdude12:06:46

not all dynlangs do this

pesterhazy12:06:51

yeah (some dimension of late binding I guess)

borkdude12:06:43

Even JS has this problem until this day:

function foo (x) { return y};
undefined
foo(1)
VM128:1 Uncaught ReferenceError: y is not defined
    at foo (<anonymous>:1:20)
    at <anonymous>:1:1

teodorlu13:06:58

perhaps this is something that could be interesting to explore as a small standalone library? Put functions in pesterhazy.process-easy, and see if you like using those instead of / in addition to babashka.process? I did some prototyping around "can we use fzf + a curated list of libraries to create a nice interface on top of neil?": https://github.com/teodorlu/neil-quickadd. I made it as a small standalone tool, and I'm currently using it myself. That way I can get hands-on experience with the thing, without anything being merged into neil. So far I really like using it. But I'm not sure whether it should be merged into Neil. It has a dependency on fzf being system-installed, which neil does not have. Also, it has a completely different interaction mechanism from Neil. Neil is a CLI, neil-quickadd is a state machine with a fzf selector. So currently, people can choose to use it, or choose to use Neil.

pesterhazy17:06:22

Nice idea @U3X7174KS – will think about it