Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

The clojure.java.shell/sh function would support InputStreams for stdin, stdout and stderr #7

Closed
wants to merge 1 commit into from

1 participant

@maxweber

Hi,

I like the comfort of clojure.java.shell/sh and would wish to be able to use it for all shell commands. Regrettably, sh only supports Strings and byte arrays to fed the sub-process's stdin and to get the results from stdout and stderr. In my use case I need to resize pictures efficiently. The scenario is something like the following:
1. Get an InputStream for the picture which is stored in a MongoDB.
2. Fed the data of the InputStream to stdin of "convert jpg:- -resize 100x100 -". The two hyphens here instructs ImageMagick to read an JPEG from stdin, resize it and stream it to stdout.
3. Get an InputStream for stdout from the underlying java.lang.Process and stream the data into the MongoDB to create a new resized picture file there.
To do this efficiently I need to leverage the java.lang.Process's stdin and stdout. The pull request contains a clojure.java.shell/sh, which supports such use cases and preserve backward compatibility to the previous version of sh. However it would be nice, if something similar would make it into the upcoming Clojure 1.3 release.

Best regards

Max Weber

@maxweber maxweber The clojure.java.shell/sh function now has the ability to copy an Inp…
…utStream directly into the stdin of the underlying java.lang.Process. Furthermore custom functions can be provided to process the stdout and stderr InputStream of the java.lang.Process.
9b8406e
@Tirael90 Tirael90 referenced this pull request in clojure-android/clojure
Closed

Android 5.0 - L #3

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 21, 2011
  1. @maxweber

    The clojure.java.shell/sh function now has the ability to copy an Inp…

    maxweber authored
    …utStream directly into the stdin of the underlying java.lang.Process. Furthermore custom functions can be provided to process the stdout and stderr InputStream of the java.lang.Process.
This page is out of date. Refresh to see the latest.
Showing with 30 additions and 8 deletions.
  1. +30 −8 src/clj/clojure/java/shell.clj
View
38 src/clj/clojure/java/shell.clj
@@ -11,7 +11,7 @@
:doc "Conveniently launch a sub-process providing its stdin and
collecting its stdout"}
clojure.java.shell
- (:use [clojure.java.io :only (as-file copy)])
+ (:use [clojure.java.io :only (as-file copy input-stream)])
(:import (java.io OutputStreamWriter ByteArrayOutputStream StringWriter)
(java.nio.charset Charset)))
@@ -82,7 +82,9 @@ collecting its stdout"}
Options are
:in may be given followed by a String or byte array specifying input
- to be fed to the sub-process's stdin.
+ to be fed to the sub-process's stdin. If :in isn't a String or
+ a byte array the value is passed to the clojure.java.io/input-stream
+ function and directly copied to the sub-process's stdin.
:in-enc option may be given followed by a String, used as a character
encoding name (for example \"UTF-8\" or \"ISO-8859-1\") to
convert the input string specified by the :in option to the
@@ -98,6 +100,16 @@ collecting its stdout"}
:env override the process env with a map (or the underlying Java
String[] if you are a masochist).
:dir override the process dir with a String or java.io.File.
+ :out-fn a custom one argument function to process the stdout
+ java.io.InputStream of the java.lang.Process. The stream
+ obtains data piped from the standard output stream (stdout) of
+ the process represented by the underlying Process object.
+ You don't need to take care of closing the java.io.InputStream.
+ :err-fn a custom one argument function to process the stderr
+ java.io.InputStream of the java.lang.Process. The stream
+ obtains data piped from the error output stream (stderr) of
+ the process represented by the underlying Process object.
+ You don't need to take care of closing the java.io.InputStream.
You can bind :env or :dir for multiple operations using with-sh-env
and with-sh-dir.
@@ -113,19 +125,29 @@ collecting its stdout"}
^"[Ljava.lang.String;" (into-array cmd)
(as-env-strings (:env opts))
(as-file (:dir opts)))
- {:keys [in in-enc out-enc]} opts]
+ {:keys [in in-enc out-enc out-fn err-fn]} opts]
(if in
(future
- (if (instance? (class (byte-array 0)) in)
+ (cond
+ (string? in)
+ (with-open [osw (OutputStreamWriter. (.getOutputStream proc) ^String in-enc)]
+ (.write osw ^String in))
+ (instance? (class (byte-array 0)) in)
(with-open [os (.getOutputStream proc)]
(.write os ^"[B" in))
- (with-open [osw (OutputStreamWriter. (.getOutputStream proc) ^String in-enc)]
- (.write osw ^String in))))
+ :else
+ (with-open [os (.getOutputStream proc)
+ is (input-stream in)]
+ (copy is os))))
(.close (.getOutputStream proc)))
(with-open [stdout (.getInputStream proc)
stderr (.getErrorStream proc)]
- (let [out (future (stream-to-enc stdout out-enc))
- err (future (stream-to-string stderr))
+ (let [out (future (if (fn? out-fn)
+ (out-fn stdout)
+ (stream-to-enc stdout out-enc)))
+ err (future (if (fn? err-fn)
+ (err-fn stderr)
+ (stream-to-string stderr)))
exit-code (.waitFor proc)]
{:exit exit-code :out @out :err @err}))))
Something went wrong with that request. Please try again.