/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ package scala package sys package process import processInternal._ import ProcessBuilder._ import scala.language.implicitConversions /** Represents a process that is running or has finished running. * It may be a compound process with several underlying native processes (such as `a #&& b`). * * This trait is often not used directly, though its companion object contains * factories for [[scala.sys.process.ProcessBuilder]], the main component of this * package. * * It is used directly when calling the method `run` on a `ProcessBuilder`, * which makes the process run in the background. The methods provided on `Process` * make it possible for one to block until the process exits and get the exit value, * or destroy the process altogether. * * Presently, one cannot poll the `Process` to see if it has finished. * * @see [[scala.sys.process.ProcessBuilder]] */ trait Process { /** Blocks until this process exits and returns the exit code.*/ def exitValue(): Int /** Destroys this process. */ def destroy(): Unit } /** Methods for constructing simple commands that can then be combined. */ object Process extends ProcessImpl with ProcessCreation { } /** Factories for creating [[scala.sys.process.ProcessBuilder]]. They can be * found on and used through [[scala.sys.process.Process]]'s companion object. */ trait ProcessCreation { /** Creates a [[scala.sys.process.ProcessBuilder]] from a `String`, including the * parameters. * * @example {{{ apply("cat file.txt") }}} */ def apply(command: String): ProcessBuilder = apply(command, None) /** Creates a [[scala.sys.process.ProcessBuilder]] from a sequence of `String`, * where the head is the command and each element of the tail is a parameter. * * @example {{{ apply("cat" :: files) }}} */ def apply(command: Seq[String]): ProcessBuilder = apply(command, None) /** Creates a [[scala.sys.process.ProcessBuilder]] from a command represented by a `String`, * and a sequence of `String` representing the arguments. * * @example {{{ apply("cat", files) }}} */ def apply(command: String, arguments: Seq[String]): ProcessBuilder = apply(command +: arguments, None) /** Creates a [[scala.sys.process.ProcessBuilder]] with working dir set to `File` and extra * environment variables. * * @example {{{ apply("java", new java.io.File("/opt/app"), "CLASSPATH" -> "library.jar") }}} */ def apply(command: String, cwd: File, extraEnv: (String, String)*): ProcessBuilder = apply(command, Some(cwd), extraEnv: _*) /** Creates a [[scala.sys.process.ProcessBuilder]] with working dir set to `File` and extra * environment variables. * * @example {{{ apply("java" :: javaArgs, new java.io.File("/opt/app"), "CLASSPATH" -> "library.jar") }}} */ def apply(command: Seq[String], cwd: File, extraEnv: (String, String)*): ProcessBuilder = apply(command, Some(cwd), extraEnv: _*) /** Creates a [[scala.sys.process.ProcessBuilder]] with working dir optionally set to * `File` and extra environment variables. * * @example {{{ apply("java", params.get("cwd"), "CLASSPATH" -> "library.jar") }}} */ def apply(command: String, cwd: Option[File], extraEnv: (String, String)*): ProcessBuilder = { apply(command.split("""\s+"""), cwd, extraEnv : _*) // not smart to use this on windows, because CommandParser uses \ to escape ". /*CommandParser.parse(command) match { case Left(errorMsg) => error(errorMsg) case Right((cmd, args)) => apply(cmd :: args, cwd, extraEnv : _*) }*/ } /** Creates a [[scala.sys.process.ProcessBuilder]] with working dir optionally set to * `File` and extra environment variables. * * @example {{{ apply("java" :: javaArgs, params.get("cwd"), "CLASSPATH" -> "library.jar") }}} */ def apply(command: Seq[String], cwd: Option[File], extraEnv: (String, String)*): ProcessBuilder = { val jpb = new JProcessBuilder(command.toArray: _*) cwd foreach (jpb directory _) extraEnv foreach { case (k, v) => jpb.environment.put(k, v) } apply(jpb) } /** Creates a [[scala.sys.process.ProcessBuilder]] from a `java.lang.ProcessBuilder`. * * @example {{{ * apply((new java.lang.ProcessBuilder("ls", "-l")) directory new java.io.File(System.getProperty("user.home"))) * }}} */ def apply(builder: JProcessBuilder): ProcessBuilder = new Simple(builder) /** Creates a [[scala.sys.process.ProcessBuilder]] from a `java.io.File`. This * `ProcessBuilder` can then be used as a `Source` or a `Sink`, so one can * pipe things from and to it. */ def apply(file: File): FileBuilder = new FileImpl(file) /** Creates a [[scala.sys.process.ProcessBuilder]] from a `java.net.URL`. This * `ProcessBuilder` can then be used as a `Source`, so that one can pipe things * from it. */ def apply(url: URL): URLBuilder = new URLImpl(url) /** Creates a [[scala.sys.process.ProcessBuilder]] from a `Boolean`. This can be * to force an exit value. */ def apply(value: Boolean): ProcessBuilder = apply(value.toString, if (value) 0 else 1) /** Creates a [[scala.sys.process.ProcessBuilder]] from a `String` name and a * `Boolean`. This can be used to force an exit value, with the name being * used for `toString`. */ def apply(name: String, exitValue: => Int): ProcessBuilder = new Dummy(name, exitValue) /** Creates a sequence of [[scala.sys.process.ProcessBuilder.Source]] from a sequence of * something else for which there's an implicit conversion to `Source`. */ def applySeq[T](builders: Seq[T])(implicit convert: T => Source): Seq[Source] = builders.map(convert) /** Creates a [[scala.sys.process.ProcessBuilder]] from one or more * [[scala.sys.process.ProcessBuilder.Source]], which can then be * piped to something else. * * This will concatenate the output of all sources. For example: * * {{{ * import scala.sys.process._ * import scala.sys.process.Process.cat * import java.net.URL * import java.io.File * * val spde = new URL("http://technically.us/spde.html") * val dispatch = new URL("http://dispatch.databinder.net/Dispatch.html") * val build = new File("project/build.properties") * cat(spde, dispatch, build) #| "grep -i scala" ! * }}} */ def cat(file: Source, files: Source*): ProcessBuilder = cat(file +: files) /** Creates a [[scala.sys.process.ProcessBuilder]] from a non-empty sequence * of [[scala.sys.process.ProcessBuilder.Source]], which can then be * piped to something else. * * This will concatenate the output of all sources. */ def cat(files: Seq[Source]): ProcessBuilder = { require(files.nonEmpty) files map (_.cat) reduceLeft (_ #&& _) } } /** Provide implicit conversions for the factories offered by [[scala.sys.process.Process]]'s * companion object. These implicits can then be used to decrease the noise in a pipeline * of commands, making it look more shell-like. They are available through the package object * [[scala.sys.process]]. */ trait ProcessImplicits { import Process._ /** Return a sequence of [[scala.sys.process.ProcessBuilder.Source]] from a sequence * of values for which an implicit conversion to `Source` is available. */ implicit def buildersToProcess[T](builders: Seq[T])(implicit convert: T => Source): Seq[Source] = applySeq(builders) /** Implicitly convert a `java.lang.ProcessBuilder` into a Scala one. */ implicit def builderToProcess(builder: JProcessBuilder): ProcessBuilder = apply(builder) /** Implicitly convert a `java.io.File` into a * [[scala.sys.process.ProcessBuilder.FileBuilder]], which can be used as * either input or output of a process. For example: * {{{ * import scala.sys.process._ * "ls" #> new java.io.File("dirContents.txt") ! * }}} */ implicit def fileToProcess(file: File): FileBuilder = apply(file) /** Implicitly convert a `java.net.URL` into a * [[scala.sys.process.ProcessBuilder.URLBuilder]] , which can be used as * input to a process. For example: * {{{ * import scala.sys.process._ * Seq("xmllint", "--html", "-") #< new java.net.URL("http://www.scala-lang.org") #> new java.io.File("fixed.html") ! * }}} */ implicit def urlToProcess(url: URL): URLBuilder = apply(url) /** Implicitly convert a `String` into a [[scala.sys.process.ProcessBuilder]]. */ implicit def stringToProcess(command: String): ProcessBuilder = apply(command) /** Implicitly convert a sequence of `String` into a * [[scala.sys.process.ProcessBuilder]]. The first argument will be taken to * be the command to be executed, and the remaining will be its arguments. * When using this, arguments may contain spaces. */ implicit def stringSeqToProcess(command: Seq[String]): ProcessBuilder = apply(command) }