@@ -5,74 +5,76 @@ import java.util.concurrent.{ArrayBlockingQueue, Semaphore, TimeUnit}
55import scala .annotation .tailrec
66
77/**
8- * Convenience APIs around [[java.lang.Process ]] and [[java.lang.ProcessBuilder ]]:
9- *
10- * - os.proc.call provides a convenient wrapper for "function-like" processes
11- * that you invoke with some input, whose entire output you need, but
12- * otherwise do not have any intricate back-and-forth communication
13- *
14- * - os.proc.stream provides a lower level API: rather than providing the output
15- * all at once, you pass in callbacks it invokes whenever there is a chunk of
16- * output received from the spawned process.
17- *
18- * - os.proc(...) provides the lowest level API: an simple Scala API around
19- * [[java.lang.ProcessBuilder ]], that spawns a normal [[java.lang.Process ]]
20- * for you to deal with. You can then interact with it normally through
21- * the standard stdin/stdout/stderr streams, using whatever protocol you
22- * want
23- */
8+ * Convenience APIs around [[java.lang.Process ]] and [[java.lang.ProcessBuilder ]]:
9+ *
10+ * - os.proc.call provides a convenient wrapper for "function-like" processes
11+ * that you invoke with some input, whose entire output you need, but
12+ * otherwise do not have any intricate back-and-forth communication
13+ *
14+ * - os.proc.stream provides a lower level API: rather than providing the output
15+ * all at once, you pass in callbacks it invokes whenever there is a chunk of
16+ * output received from the spawned process.
17+ *
18+ * - os.proc(...) provides the lowest level API: an simple Scala API around
19+ * [[java.lang.ProcessBuilder ]], that spawns a normal [[java.lang.Process ]]
20+ * for you to deal with. You can then interact with it normally through
21+ * the standard stdin/stdout/stderr streams, using whatever protocol you
22+ * want
23+ */
2424case class proc (command : Shellable * ) {
2525 def commandChunks : Seq [String ] = command.flatMap(_.value)
2626
2727 /**
28- * Invokes the given subprocess like a function, passing in input and returning a
29- * [[CommandResult ]]. You can then call `result.exitCode` to see how it exited, or
30- * `result.out.bytes` or `result.err.string` to access the aggregated stdout and
31- * stderr of the subprocess in a number of convenient ways. If a non-zero exit code
32- * is returned, this throws a [[os.SubprocessException ]] containing the
33- * [[CommandResult ]], unless you pass in `check = false`.
34- *
35- * If you want to spawn an interactive subprocess, such as `vim`, `less`, or a
36- * `python` shell, set all of `stdin`/`stdout`/`stderr` to [[os.Inherit ]]
37- *
38- * `call` provides a number of parameters that let you configure how the subprocess
39- * is run:
40- *
41- * @param cwd the working directory of the subprocess
42- * @param env any additional environment variables you wish to set in the subprocess
43- * @param stdin any data you wish to pass to the subprocess's standard input
44- * @param stdout How the process's output stream is configured.
45- * @param stderr How the process's error stream is configured.
46- * @param mergeErrIntoOut merges the subprocess's stderr stream into it's stdout
47- * @param timeout how long to wait in milliseconds for the subprocess to complete
48- * @param check disable this to avoid throwing an exception if the subprocess
49- * fails with a non-zero exit code
50- * @param propagateEnv disable this to avoid passing in this parent process's
51- * environment variables to the subprocess
52- */
53- def call (cwd : Path = null ,
54- env : Map [String , String ] = null ,
55- stdin : ProcessInput = Pipe ,
56- stdout : ProcessOutput = Pipe ,
57- stderr : ProcessOutput = os.Inherit ,
58- mergeErrIntoOut : Boolean = false ,
59- timeout : Long = - 1 ,
60- check : Boolean = true ,
61- propagateEnv : Boolean = true )
62- : CommandResult = {
28+ * Invokes the given subprocess like a function, passing in input and returning a
29+ * [[CommandResult ]]. You can then call `result.exitCode` to see how it exited, or
30+ * `result.out.bytes` or `result.err.string` to access the aggregated stdout and
31+ * stderr of the subprocess in a number of convenient ways. If a non-zero exit code
32+ * is returned, this throws a [[os.SubprocessException ]] containing the
33+ * [[CommandResult ]], unless you pass in `check = false`.
34+ *
35+ * If you want to spawn an interactive subprocess, such as `vim`, `less`, or a
36+ * `python` shell, set all of `stdin`/`stdout`/`stderr` to [[os.Inherit ]]
37+ *
38+ * `call` provides a number of parameters that let you configure how the subprocess
39+ * is run:
40+ *
41+ * @param cwd the working directory of the subprocess
42+ * @param env any additional environment variables you wish to set in the subprocess
43+ * @param stdin any data you wish to pass to the subprocess's standard input
44+ * @param stdout How the process's output stream is configured.
45+ * @param stderr How the process's error stream is configured.
46+ * @param mergeErrIntoOut merges the subprocess's stderr stream into it's stdout
47+ * @param timeout how long to wait in milliseconds for the subprocess to complete
48+ * @param check disable this to avoid throwing an exception if the subprocess
49+ * fails with a non-zero exit code
50+ * @param propagateEnv disable this to avoid passing in this parent process's
51+ * environment variables to the subprocess
52+ */
53+ def call (
54+ cwd : Path = null ,
55+ env : Map [String , String ] = null ,
56+ stdin : ProcessInput = Pipe ,
57+ stdout : ProcessOutput = Pipe ,
58+ stderr : ProcessOutput = os.Inherit ,
59+ mergeErrIntoOut : Boolean = false ,
60+ timeout : Long = - 1 ,
61+ check : Boolean = true ,
62+ propagateEnv : Boolean = true
63+ ): CommandResult = {
6364
6465 val chunks = new java.util.concurrent.ConcurrentLinkedQueue [Either [geny.Bytes , geny.Bytes ]]
6566
6667 val sub = spawn(
67- cwd, env,
68+ cwd,
69+ env,
6870 stdin,
6971 if (stdout ne os.Pipe ) stdout
70- else os.ProcessOutput .ReadBytes (
71- (buf, n) => chunks.add(Left (new geny.Bytes (java.util.Arrays .copyOf(buf, n))))
72+ else os.ProcessOutput .ReadBytes ((buf, n) =>
73+ chunks.add(Left (new geny.Bytes (java.util.Arrays .copyOf(buf, n))))
7274 ),
7375 if (stderr ne os.Pipe ) stderr
74- else os.ProcessOutput .ReadBytes (
75- (buf, n) => chunks.add(Right (new geny.Bytes (java.util.Arrays .copyOf(buf, n))))
76+ else os.ProcessOutput .ReadBytes ((buf, n) =>
77+ chunks.add(Right (new geny.Bytes (java.util.Arrays .copyOf(buf, n))))
7678 ),
7779 mergeErrIntoOut,
7880 propagateEnv
@@ -88,31 +90,33 @@ case class proc(command: Shellable*) {
8890 }
8991
9092 /**
91- * The most flexible of the [[os.proc ]] calls, `os.proc.spawn` simply configures
92- * and starts a subprocess, and returns it as a `java.lang.Process` for you to
93- * interact with however you like.
94- *
95- * To implement pipes, you can spawn a process, take it's stdout, and pass it
96- * as the stdin of a second spawned process.
97- *
98- * Note that if you provide `ProcessOutput` callbacks to `stdout`/`stderr`,
99- * the calls to those callbacks take place on newly spawned threads that
100- * execute in parallel with the main thread. Thus make sure any data
101- * processing you do in those callbacks is thread safe!
102- */
103- def spawn (cwd : Path = null ,
104- env : Map [String , String ] = null ,
105- stdin : ProcessInput = Pipe ,
106- stdout : ProcessOutput = Pipe ,
107- stderr : ProcessOutput = os.Inherit ,
108- mergeErrIntoOut : Boolean = false ,
109- propagateEnv : Boolean = true ): SubProcess = {
93+ * The most flexible of the [[os.proc ]] calls, `os.proc.spawn` simply configures
94+ * and starts a subprocess, and returns it as a `java.lang.Process` for you to
95+ * interact with however you like.
96+ *
97+ * To implement pipes, you can spawn a process, take it's stdout, and pass it
98+ * as the stdin of a second spawned process.
99+ *
100+ * Note that if you provide `ProcessOutput` callbacks to `stdout`/`stderr`,
101+ * the calls to those callbacks take place on newly spawned threads that
102+ * execute in parallel with the main thread. Thus make sure any data
103+ * processing you do in those callbacks is thread safe!
104+ */
105+ def spawn (
106+ cwd : Path = null ,
107+ env : Map [String , String ] = null ,
108+ stdin : ProcessInput = Pipe ,
109+ stdout : ProcessOutput = Pipe ,
110+ stderr : ProcessOutput = os.Inherit ,
111+ mergeErrIntoOut : Boolean = false ,
112+ propagateEnv : Boolean = true
113+ ): SubProcess = {
110114 val builder = new java.lang.ProcessBuilder ()
111115
112116 val baseEnv =
113117 if (propagateEnv) sys.env
114118 else Map ()
115- for ((k, v) <- baseEnv ++ Option (env).getOrElse(Map ())){
119+ for ((k, v) <- baseEnv ++ Option (env).getOrElse(Map ())) {
116120 if (v != null ) builder.environment().put(k, v)
117121 else builder.environment().remove(k)
118122 }
@@ -123,7 +127,7 @@ case class proc(command: Shellable*) {
123127 val commandStr = cmdChunks.mkString(" " )
124128 lazy val proc : SubProcess = new SubProcess (
125129 builder
126- .command(cmdChunks:_* )
130+ .command(cmdChunks : _* )
127131 .redirectInput(stdin.redirectFrom)
128132 .redirectOutput(stdout.redirectTo)
129133 .redirectError(stderr.redirectTo)
0 commit comments