Created
April 30, 2014 00:03
-
-
Save aturon/1a17763ab8d8aa3f1124 to your computer and use it in GitHub Desktop.
draft ProcessBuilder implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// This process builder type provides fine-grained control over how a new | |
/// process should be spawned. A default configuration can be generated using | |
/// `ProcessBuilder::new(program)`, where `program` gives a path to the program | |
/// to be executed. Additional builder methods allow the configuration to be | |
/// changed (for example, by adding arguments) prior to spawning: | |
/// | |
/// ``` | |
/// use std:io::ProcessBuilder; | |
/// | |
/// let mut process = match ProcessBuilder.new("sh").arg("-c").arg("echo hello").spawn() { | |
/// Ok(p) => p | |
/// Err(e) => fail!("failed to execute process: {}", e), | |
/// }; | |
/// | |
/// let output = process.stdout.get_mut_ref().read_to_end(); | |
/// ``` | |
pub struct ProcessBuilder { | |
// The meaning of these configuration options is documented by the | |
// constructor and builder methods below. | |
program: CString, | |
args: Vec<CString>, | |
inherit_env: bool, | |
env: Vec<(CString, CString)>, | |
cwd: Option<Path>, | |
stdin: StdioContainer, | |
stdout: StdioContainer, | |
stderr: StdioContainer, | |
extra_io: Vec<StdioContainer>, | |
uid: Option<uint>, | |
gid: Option<uint>, | |
detach: bool, | |
} | |
impl ProcessBuilder { | |
/// Constructs a new `ProcessBuilder` for launching the program at | |
/// path `program`, with the following default configuration: | |
/// | |
/// * No arguments to the program | |
/// * Inherit the current process's environment | |
/// * Inherit the current process's working directory | |
/// * A readable pipe for stdin (file descriptor 0) | |
/// * A writeable pipe for stdour and stderr (file descriptors 1 and 2) | |
/// | |
/// Builder methods are provided to change these defaults and | |
/// otherwise configure the process. | |
fn new<T:ToCStr>(program: T) -> ProcessBuilder { | |
ProcessBuilder { | |
program: program, | |
args: Vec::new(), | |
inherit_env: true, | |
env: Vec::new(), | |
cwd: None, | |
stdin: CreatePipe(true, false), | |
stdout: CreatePipe(false, true), | |
stderr: CreatePipe(false, true), | |
extra_io: Vec::new(), | |
uid: None, | |
gid: None, | |
detach: false, | |
} | |
} | |
/// Add an argument to pass to the program | |
fn arg<T:ToCStr>(mut self, arg: &T) -> ProcessBuilder { | |
self.args.push(arg.to_c_str()); | |
self | |
} | |
/// Determines whether the current process's environment is inherited by the | |
/// child process | |
fn inherit_env(mut self, inherit: bool) -> ProcessBuilder { | |
self.inheric_env = inherit; | |
self | |
} | |
/// Add an environment variable to the child process | |
fn env<T:ToCStr>(mut self, name: &T, val: &T) -> ProcessBuilder { | |
self.env.push((name.to_c_str(), val.to_c_str())); | |
self | |
} | |
/// Set the working directory for the child process | |
fn cwd(mut self, dir: Path) -> ProcessBuilder { | |
self.cwd = Some(dir); | |
self | |
} | |
/// Configuration for the child process's stdin handle (file descriptor 0). | |
/// Defaults to `CreatePipe(true, false)` so the input can be written to. | |
fn stdin(mut self, cfg: StdioContainer) -> ProcessBuilder { | |
self.stdin = cfg; | |
self | |
} | |
/// Configuration for the child process's stdout handle (file descriptor 1). | |
/// Defaults to `CreatePipe(false, true)` so the output can be collected. | |
fn stdout(mut self, cfg: StdioContainer) -> ProcessBuilder { | |
self.stdout = cfg; | |
self | |
} | |
/// Configuration for the child process's stderr handle (file descriptor 2). | |
/// Defaults to `CreatePipe(false, true)` so the output can be collected. | |
fn stderr(mut self, cfg: StdioContainer) -> ProcessBuilder { | |
self.stderr = cfg; | |
self | |
} | |
/// Attaches a stream/file descriptor/pipe to the child process. Inherited | |
/// file descriptors are numbered consecutively, starting at 3; the first | |
/// three file descriptors (stdin/stdout/stderr) are configured with the | |
/// `stdin`, `stdout`, and `stderr` methods. | |
fn extra_io(mut self, cfg: StdioContainer) -> ProcessBuilder { | |
self.extra_io.push(cfg); | |
self | |
} | |
/// Sets the child process's user id. This translates to a `setuid` call in | |
/// the child process. Setting this value on windows will cause the spawn to | |
/// fail. Failure in the `setuid` call on unix will also cause the spawn to | |
/// fail. | |
fn uid(mut self, id: uint) -> ProcessBuilder { | |
self.uid = Some(id); | |
self | |
} | |
/// Similar to `uid`, but sets the group id of the child process. This has | |
/// the same semantics as the `uid` field. | |
fn gid(mut self, id: uint) -> ProcessBuilder { | |
self.gid = Some(id); | |
self | |
} | |
/// Sets the child process to be spawned in a detached state. On unix, this | |
/// means that the child is the leader of a new process group. | |
fn detached(mut self) -> ProcessBuilder { | |
self.detach = true; | |
self | |
} | |
/// Actually spawn the process, while consuming the builder. | |
fn spawn(self) -> IOResult<Process> { | |
let mut config = Some(self); | |
LocalIo::maybe_raise(|io| { | |
io.spawn(config.take_unwrap()).map(|(p, io)| { | |
let mut io = io.move_iter().map(|p| { | |
p.map(|p| io::PipeStream::new(p)) | |
}); | |
Process { | |
handle: p, | |
stdin: io.next().unwrap(), | |
stdout: io.next().unwrap(), | |
stderr: io.next().unwrap(), | |
extra_io: io.collect(), | |
} | |
}) | |
}) | |
} | |
// todo: add output and status | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment