2016-12-18 17:58:46 -08:00
|
|
|
//! An implementation of process management for Tokio.
|
|
|
|
|
//!
|
|
|
|
|
//! This crate provides `Future` implementations for spawning and waiting
|
|
|
|
|
//! on child processes. These implementations are powered by system APIs on
|
|
|
|
|
//! Windows and by signals on Unix systems.
|
|
|
|
|
//!
|
|
|
|
|
//! # Usage
|
|
|
|
|
//!
|
|
|
|
|
//! To achieve efficient polling of running child processes, we will need to
|
|
|
|
|
//! set up an event loop from `tokio-core`:
|
|
|
|
|
// FIXME: add warning that on Unix systems the *first* event loop can't go away?
|
|
|
|
|
//!
|
|
|
|
|
//! ```no_run
|
|
|
|
|
//! extern crate futures;
|
|
|
|
|
//! extern crate tokio_core;
|
|
|
|
|
//! extern crate tokio_process;
|
|
|
|
|
//!
|
|
|
|
|
//! use futures::Future;
|
|
|
|
|
//! use tokio_core::reactor::Core;
|
|
|
|
|
//! use tokio_process::Command;
|
|
|
|
|
//!
|
|
|
|
|
//! fn main() {
|
|
|
|
|
//! let mut event_loop = Core::new().expect("failed to init event loop!");
|
|
|
|
|
//! let mut cmd = Command::new("echo", &event_loop.handle());
|
|
|
|
|
//! cmd.args(&["hello", "world"]);
|
|
|
|
|
//!
|
|
|
|
|
//! match event_loop.run(cmd.spawn().flatten()) {
|
|
|
|
|
//! Ok(status) => println!("exited successfully: {}", status.success()),
|
|
|
|
|
//! Err(e) => panic!("failed to run command: {}", e),
|
|
|
|
|
//! }
|
|
|
|
|
//! }
|
|
|
|
|
//! ```
|
|
|
|
|
|
2016-09-07 00:13:11 -07:00
|
|
|
#[macro_use]
|
|
|
|
|
extern crate futures;
|
|
|
|
|
extern crate tokio_core;
|
2016-11-18 20:57:31 +01:00
|
|
|
extern crate mio;
|
2016-12-04 18:47:48 +01:00
|
|
|
#[macro_use]
|
|
|
|
|
extern crate log;
|
2016-09-07 00:13:11 -07:00
|
|
|
|
|
|
|
|
use std::ffi::OsStr;
|
2016-12-12 00:34:07 -08:00
|
|
|
use std::io::{self, Read, Write};
|
2016-09-07 00:13:11 -07:00
|
|
|
use std::path::Path;
|
|
|
|
|
use std::process::{self, ExitStatus};
|
|
|
|
|
|
|
|
|
|
use futures::{Future, Poll};
|
2016-09-07 22:15:13 -07:00
|
|
|
use tokio_core::reactor::Handle;
|
2016-09-07 00:13:11 -07:00
|
|
|
|
|
|
|
|
#[path = "unix.rs"]
|
2016-09-07 12:04:46 -07:00
|
|
|
#[cfg(unix)]
|
|
|
|
|
mod imp;
|
|
|
|
|
|
|
|
|
|
#[path = "windows.rs"]
|
|
|
|
|
#[cfg(windows)]
|
2016-09-07 00:13:11 -07:00
|
|
|
mod imp;
|
|
|
|
|
|
|
|
|
|
pub struct Command {
|
|
|
|
|
inner: process::Command,
|
2016-09-07 12:04:46 -07:00
|
|
|
#[allow(dead_code)]
|
2016-09-07 22:15:13 -07:00
|
|
|
handle: Handle,
|
2016-09-07 00:13:11 -07:00
|
|
|
}
|
|
|
|
|
|
2016-12-18 17:58:46 -08:00
|
|
|
/// A future that represents a spawned child process.
|
|
|
|
|
///
|
|
|
|
|
/// This future is created by the `Command::spawn` method.
|
|
|
|
|
///
|
|
|
|
|
/// If the caller does not care about the intermediate handle to a spawned
|
|
|
|
|
/// child, this future can be `flatten`ed to directly compute the child's
|
|
|
|
|
/// exit status.
|
2016-09-07 00:13:11 -07:00
|
|
|
pub struct Spawn {
|
|
|
|
|
inner: Box<Future<Item=Child, Error=io::Error>>,
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-18 17:58:46 -08:00
|
|
|
/// A future that represents the exit status of a running or exited child process.
|
|
|
|
|
///
|
|
|
|
|
/// This future is created by successfully polling the `Spawn` future.
|
|
|
|
|
///
|
|
|
|
|
/// # Note
|
|
|
|
|
///
|
|
|
|
|
/// Take note that there is no implementation of `Drop` for this future,
|
|
|
|
|
/// so if you do not ensure the `Child` has exited then it will continue to
|
|
|
|
|
/// run, even after the `Child` handle to the child process has gone out of
|
|
|
|
|
/// scope.
|
2016-09-07 00:13:11 -07:00
|
|
|
pub struct Child {
|
|
|
|
|
inner: imp::Child,
|
2016-12-12 00:34:07 -08:00
|
|
|
stdin: Option<ChildStdin>,
|
|
|
|
|
stdout: Option<ChildStdout>,
|
|
|
|
|
stderr: Option<ChildStderr>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ChildStdin {
|
|
|
|
|
inner: imp::ChildStdin,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ChildStdout {
|
|
|
|
|
inner: imp::ChildStdout,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ChildStderr {
|
|
|
|
|
inner: imp::ChildStderr,
|
2016-09-07 00:13:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Command {
|
2016-09-07 22:15:13 -07:00
|
|
|
pub fn new<T: AsRef<OsStr>>(exe: T, handle: &Handle) -> Command {
|
2016-09-07 00:13:11 -07:00
|
|
|
Command::_new(exe.as_ref(), handle)
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 22:15:13 -07:00
|
|
|
fn _new(exe: &OsStr, handle: &Handle) -> Command {
|
2016-09-07 00:13:11 -07:00
|
|
|
Command {
|
|
|
|
|
inner: process::Command::new(exe),
|
|
|
|
|
handle: handle.clone(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
|
|
|
|
|
self._arg(arg.as_ref())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn _arg(&mut self, arg: &OsStr) -> &mut Command {
|
|
|
|
|
self.inner.arg(arg);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command {
|
|
|
|
|
for arg in args {
|
|
|
|
|
self._arg(arg.as_ref());
|
|
|
|
|
}
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
|
|
|
|
|
where K: AsRef<OsStr>, V: AsRef<OsStr>
|
|
|
|
|
{
|
|
|
|
|
self._env(key.as_ref(), val.as_ref())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn _env(&mut self, key: &OsStr, val: &OsStr) -> &mut Command {
|
|
|
|
|
self.inner.env(key, val);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
|
|
|
|
|
self._env_remove(key.as_ref())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn _env_remove(&mut self, key: &OsStr) -> &mut Command {
|
|
|
|
|
self.inner.env_remove(key);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn env_clear(&mut self) -> &mut Command {
|
|
|
|
|
self.inner.env_clear();
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
|
|
|
|
|
self._current_dir(dir.as_ref())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn _current_dir(&mut self, dir: &Path) -> &mut Command {
|
|
|
|
|
self.inner.current_dir(dir);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-18 20:57:31 +01:00
|
|
|
pub fn stdin(&mut self, cfg: process::Stdio) -> &mut Self {
|
|
|
|
|
self.inner.stdin(cfg);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn stdout(&mut self, cfg: process::Stdio) -> &mut Self {
|
|
|
|
|
self.inner.stdout(cfg);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
pub fn stderr(&mut self, cfg: process::Stdio) -> &mut Self {
|
|
|
|
|
self.inner.stderr(cfg);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 00:13:11 -07:00
|
|
|
pub fn spawn(self) -> Spawn {
|
|
|
|
|
Spawn {
|
2016-12-12 00:34:07 -08:00
|
|
|
inner: Box::new(imp::spawn(self)),
|
2016-09-07 00:13:11 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Future for Spawn {
|
|
|
|
|
type Item = Child;
|
|
|
|
|
type Error = io::Error;
|
|
|
|
|
|
|
|
|
|
fn poll(&mut self) -> Poll<Child, io::Error> {
|
|
|
|
|
self.inner.poll()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Child {
|
2016-12-18 17:58:46 -08:00
|
|
|
/// Returns the OS-assigned process identifier associated with this child.
|
2016-09-07 00:13:11 -07:00
|
|
|
pub fn id(&self) -> u32 {
|
|
|
|
|
self.inner.id()
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-18 17:58:46 -08:00
|
|
|
/// Forces the child to exit. This is equivalent to sending a
|
|
|
|
|
/// SIGKILL on unix platforms.
|
2016-09-07 00:13:11 -07:00
|
|
|
pub fn kill(&mut self) -> io::Result<()> {
|
|
|
|
|
self.inner.kill()
|
|
|
|
|
}
|
2016-11-18 20:57:31 +01:00
|
|
|
|
2016-12-12 00:34:07 -08:00
|
|
|
pub fn stdin(&mut self) -> &mut Option<ChildStdin> {
|
|
|
|
|
&mut self.stdin
|
2016-11-18 20:57:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-12 00:34:07 -08:00
|
|
|
pub fn stdout(&mut self) -> &mut Option<ChildStdout> {
|
|
|
|
|
&mut self.stdout
|
2016-11-18 20:57:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-12 00:34:07 -08:00
|
|
|
pub fn stderr(&mut self) -> &mut Option<ChildStderr> {
|
|
|
|
|
&mut self.stderr
|
2016-11-18 20:57:31 +01:00
|
|
|
}
|
2016-09-07 00:13:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Future for Child {
|
|
|
|
|
type Item = ExitStatus;
|
|
|
|
|
type Error = io::Error;
|
|
|
|
|
|
|
|
|
|
fn poll(&mut self) -> Poll<ExitStatus, io::Error> {
|
|
|
|
|
self.inner.poll()
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-12 00:34:07 -08:00
|
|
|
|
|
|
|
|
impl Write for ChildStdin {
|
|
|
|
|
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
|
|
|
|
|
self.inner.write(bytes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
|
|
|
self.inner.flush()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Read for ChildStdout {
|
|
|
|
|
fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
|
|
|
|
|
self.inner.read(bytes)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Read for ChildStderr {
|
|
|
|
|
fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
|
|
|
|
|
self.inner.read(bytes)
|
|
|
|
|
}
|
|
|
|
|
}
|