Welcome! Please see the About page for a little more info on how this works.

+11 votes
in IO by
retagged by

The newest Clojure alpha added a clojure.java.process namespace. I had a need for better process spawning handling in a Clojure program I'm working on, so I investigated if it makes sense to update my Clojure dependency to 1.12.0-alpha2, and I want to give you feedback on functionality and bugs I encountered when evaluating this namespace.

  1. Error stream -> stdout redirection does not work
    When supplying :err :stdout opt, the launched process does not redirect the output to stdout, because (.redirectErrorStream pb) on line 89 is a getter. It should be (.redirectErrorStream pb true) instead. You can test it with (exec {:out :inherit :err :stdout} "bash" "-c" "ls >&2")

  2. There is no way to remove env vars
    Removing env vars is a useful feature when launching the process, and it's even documented in an example in ProcessBuilder's Javadoc. I suggest adding support for the removal of env vars by treating nil env values as a request to remove the env var from the launched process env.

  3. It's impossible to override exec's :err :inherit option
    Exec documentation states that it's possible to override exec's default options, but on line 137 the default options take precedence over user-supplied options, it should be (merge {:err :inherit} opts) instead.

  4. Capture kv-opt is :buffer-size, not :buffer
    On line 119, capture docstring says that its kv-opts are the same as in jio/copy:buffer and :encoding, but jio/copy's kv-opts are :buffer-size and :encoding.

  5. Nitpick: checks for the truthiness of in/out/err/dir are unnecessary
    Lines 85-90 perform checks if the opts exist, which is unnecessary because defaults are provided on line 75

Just a sidenote:

babashka.process has :env and :extra-env. :env replaces the environment (which allows you to copy the current System/getenv and remove stuff from that) and :extra-env only adds environment variables. Like ProcessBuilder, :env defaults to System/getenv initially.

E.g. to remove env vars:

(require '[babashka.process :as p])

(let [env (-> (into {} (System/getenv))
              (dissoc "PATH"))]
  (p/shell {:env env} "bash" "-c" "echo $PATH"))

It's a little more verbose than the nil option, which I also like.

1 Answer