diff options
author | Paul Phillips <paulp@improving.org> | 2009-08-26 17:06:23 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-08-26 17:06:23 +0000 |
commit | a4e8b0a50296c91d943a1d049719e9bd80500e23 (patch) | |
tree | 8d5ea8bb6b806635622e84633e54b4b0c890ea7c | |
parent | fd58ffc924878e36a9d1dfdd9a8a2f169fd77b97 (diff) | |
download | scala-a4e8b0a50296c91d943a1d049719e9bd80500e23.tar.gz scala-a4e8b0a50296c91d943a1d049719e9bd80500e23.tar.bz2 scala-a4e8b0a50296c91d943a1d049719e9bd80500e23.zip |
Initial implementation of scala.io.Process.
-rw-r--r-- | src/dotnet-library/scala/io/Process.scala | 1 | ||||
-rw-r--r-- | src/library/scala/io/Process.scala | 123 |
2 files changed, 124 insertions, 0 deletions
diff --git a/src/dotnet-library/scala/io/Process.scala b/src/dotnet-library/scala/io/Process.scala new file mode 100644 index 0000000000..dda8821199 --- /dev/null +++ b/src/dotnet-library/scala/io/Process.scala @@ -0,0 +1 @@ +/* Process.scala does not exist for the dotnet target */
\ No newline at end of file diff --git a/src/library/scala/io/Process.scala b/src/library/scala/io/Process.scala new file mode 100644 index 0000000000..a47b7b39d8 --- /dev/null +++ b/src/library/scala/io/Process.scala @@ -0,0 +1,123 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.io + +import annotation.experimental +import concurrent.ThreadRunner +import util.Properties.{ isWin, isMac } +import util.control.Exception.catching +import java.lang.{ Process => JProcess, ProcessBuilder => JProcessBuilder } +import java.io.{ InputStream, OutputStream, BufferedReader, InputStreamReader, File => JFile } + +/** The <code>Process</code> object contains convenience functions + * for running external processes. + * + * An example usage: + * <pre> + * io.Process.shell("ls", cwd = io.File("/")) foreach println + * </pre> + * + * See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4109888 + * for a dated list of the many obstacles to a clean interface. + * +|* This is not finished!! Do not rely upon it yet. + * + * @author Paul Phillips + * @since 2.8 + */ + +@experimental +object Process +{ + lazy val runtime = Runtime.getRuntime() + + @experimental + private[Process] class ProcessBuilder(val pb: JProcessBuilder) + { + def this(cmd: String*) = this(new JProcessBuilder(cmd.toArray: _*)) + + def withOnlyEnv(env: Map[String, String]): this.type = { + pb.environment.clear() + withEnv(env) + } + + def withEnv(env: Map[String,String]): this.type = { + if (env != null) { + val jmap = pb.environment() + for ((k, v) <- env) jmap.put(k, v) + } + this + } + + def withCwd(cwd: File): this.type = { + if (cwd != null) + pb directory cwd.file + + this + } + + def start(): Process = new Process(pb.start()) + } + + // This can be fleshed out if more variations come up + private val shell: String => Array[String] = + if (isWin) Array("cmd.exe", "/C", _) + else Array("sh", "-c", _) + + /** Executes the given command line in a shell. + * + * @param command the command line + * @return a Process object + */ + def shell( + command: String, + env: Map[String, String] = null, + cwd: File = null + ): Process = + apply(shell(command), env, cwd) + + /** Executes the given command line. + * + * @param command the command line + * @return a Process object + */ + def apply( + command: Seq[String], + env: Map[String, String] = null, + cwd: File = null + ): Process = + new ProcessBuilder(command: _*) withEnv env withCwd cwd start +} +import Process._ + +@experimental +class Process(val process: JProcess) extends Iterable[String] +{ + class StreamedConsumer(in: InputStream) extends Thread with Iterable[String] { + private val reader = new BufferedReader(new InputStreamReader(in)) + private lazy val stream: Stream[String] = + Stream continually reader.readLine takeWhile (_ != null) + + // call/block on force in case it's not done collecting output + def iterator = stream.force.iterator + override def run() { stream.force } + def slurp() = { this.start() ; this } + } + + private val _err = new StreamedConsumer(process.getErrorStream).slurp() + private val _out = new StreamedConsumer(process.getInputStream).slurp() + + def exitValue(): Option[Int] = + catching(classOf[IllegalThreadStateException]) opt process.exitValue() + + def iterator = _out.iterator + def err = _err.iterator + override def toString() = "Process(%s)" format process.toString() +} + |