#![warn(missing_debug_implementations)]
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/tokio-process/0.1")]
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate mio;
use std::ffi::OsStr;
use std::io::{self, Read, Write};
use std::path::Path;
use std::process::{self, ExitStatus, Output, Stdio};
use futures::{Future, Poll, IntoFuture};
use futures::future::{Flatten, FutureResult, Either, ok};
use std::fmt;
use tokio_core::reactor::Handle;
use tokio_io::io::{read_to_end};
use tokio_io::{AsyncWrite, AsyncRead, IoFuture};
#[path = "unix.rs"]
#[cfg(unix)]
mod imp;
#[path = "windows.rs"]
#[cfg(windows)]
mod imp;
pub trait CommandExt {
fn spawn_async(&mut self, handle: &Handle) -> io::Result<Child>;
#[deprecated(note = "use the more flexible `spawn_async2` method instead")]
#[allow(deprecated)]
fn status_async(&mut self, handle: &Handle) -> StatusAsync;
fn status_async2(&mut self, handle: &Handle) -> io::Result<StatusAsync2>;
fn output_async(&mut self, handle: &Handle) -> OutputAsync;
}
impl CommandExt for process::Command {
fn spawn_async(&mut self, handle: &Handle) -> io::Result<Child> {
let mut child = Child {
child: imp::Child::new(try!(self.spawn()), handle),
stdin: None,
stdout: None,
stderr: None,
kill_on_drop: true,
};
child.stdin = try!(child.child.register_stdin(handle)).map(|io| {
ChildStdin { inner: io }
});
child.stdout = try!(child.child.register_stdout(handle)).map(|io| {
ChildStdout { inner: io }
});
child.stderr = try!(child.child.register_stderr(handle)).map(|io| {
ChildStderr { inner: io }
});
Ok(child)
}
#[allow(deprecated)]
fn status_async(&mut self, handle: &Handle) -> StatusAsync {
let mut inner = self.spawn_async(handle);
if let Ok(child) = inner.as_mut() {
child.stdin.take();
child.stdout.take();
child.stderr.take();
}
StatusAsync {
inner: inner.into_future().flatten(),
}
}
fn status_async2(&mut self, handle: &Handle) -> io::Result<StatusAsync2> {
self.spawn_async(handle).map(|mut child| {
child.stdin.take();
child.stdout.take();
child.stderr.take();
StatusAsync2 {
inner: child,
}
})
}
fn output_async(&mut self, handle: &Handle) -> OutputAsync {
self.stdout(Stdio::piped());
self.stderr(Stdio::piped());
OutputAsync {
inner: Box::new(self.spawn_async(handle).into_future().and_then(|c| {
c.wait_with_output()
})),
}
}
}
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct Child {
child: imp::Child,
kill_on_drop: bool,
stdin: Option<ChildStdin>,
stdout: Option<ChildStdout>,
stderr: Option<ChildStderr>,
}
impl Child {
pub fn id(&self) -> u32 {
self.child.id()
}
pub fn kill(&mut self) -> io::Result<()> {
self.child.kill()
}
pub fn stdin(&mut self) -> &mut Option<ChildStdin> {
&mut self.stdin
}
pub fn stdout(&mut self) -> &mut Option<ChildStdout> {
&mut self.stdout
}
pub fn stderr(&mut self) -> &mut Option<ChildStderr> {
&mut self.stderr
}
pub fn wait_with_output(mut self) -> WaitWithOutput {
drop(self.stdin().take());
let stdout = match self.stdout().take() {
Some(io) => Either::A(read_to_end(io, Vec::new()).map(|p| p.1)),
None => Either::B(ok(Vec::new())),
};
let stderr = match self.stderr().take() {
Some(io) => Either::A(read_to_end(io, Vec::new()).map(|p| p.1)),
None => Either::B(ok(Vec::new())),
};
WaitWithOutput {
inner: Box::new(self.join3(stdout, stderr).map(|(status, stdout, stderr)| {
Output {
status: status,
stdout: stdout,
stderr: stderr,
}
}))
}
}
pub fn forget(mut self) {
self.kill_on_drop = false;
}
}
impl Future for Child {
type Item = ExitStatus;
type Error = io::Error;
fn poll(&mut self) -> Poll<ExitStatus, io::Error> {
self.child.poll_exit()
}
}
impl Drop for Child {
fn drop(&mut self) {
if self.kill_on_drop {
drop(self.kill());
}
}
}
#[must_use = "futures do nothing unless polled"]
pub struct WaitWithOutput {
inner: IoFuture<Output>,
}
impl fmt::Debug for WaitWithOutput {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("WaitWithOutput")
.field("inner", &"..")
.finish()
}
}
impl Future for WaitWithOutput {
type Item = Output;
type Error = io::Error;
fn poll(&mut self) -> Poll<Output, io::Error> {
self.inner.poll()
}
}
#[must_use = "futures do nothing unless polled"]
#[deprecated(note = "use the more flexible `SpawnAsync2` adapter instead")]
#[allow(deprecated)]
#[derive(Debug)]
pub struct StatusAsync {
inner: Flatten<FutureResult<Child, io::Error>>,
}
#[allow(deprecated)]
impl Future for StatusAsync {
type Item = ExitStatus;
type Error = io::Error;
fn poll(&mut self) -> Poll<ExitStatus, io::Error> {
self.inner.poll()
}
}
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct StatusAsync2 {
inner: Child,
}
impl Future for StatusAsync2 {
type Item = ExitStatus;
type Error = io::Error;
fn poll(&mut self) -> Poll<ExitStatus, io::Error> {
self.inner.poll()
}
}
#[must_use = "futures do nothing unless polled"]
pub struct OutputAsync {
inner: IoFuture<Output>,
}
impl fmt::Debug for OutputAsync {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("OutputAsync")
.field("inner", &"..")
.finish()
}
}
impl Future for OutputAsync {
type Item = Output;
type Error = io::Error;
fn poll(&mut self) -> Poll<Output, io::Error> {
self.inner.poll()
}
}
#[derive(Debug)]
pub struct ChildStdin {
inner: imp::ChildStdin,
}
#[derive(Debug)]
pub struct ChildStdout {
inner: imp::ChildStdout,
}
#[derive(Debug)]
pub struct ChildStderr {
inner: imp::ChildStderr,
}
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 AsyncWrite for ChildStdin {
fn shutdown(&mut self) -> Poll<(), io::Error> {
self.inner.shutdown()
}
}
impl Read for ChildStdout {
fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
self.inner.read(bytes)
}
}
impl AsyncRead for ChildStdout {
}
impl Read for ChildStderr {
fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
self.inner.read(bytes)
}
}
impl AsyncRead for ChildStderr {
}
#[deprecated(note = "use std::process::Command instead")]
#[allow(deprecated, missing_docs)]
#[allow(deprecated, missing_debug_implementations, missing_docs)]
#[doc(hidden)]
pub struct Command {
inner: process::Command,
#[allow(dead_code)]
handle: Handle,
}
#[deprecated(note = "use std::process::Command instead")]
#[allow(deprecated, missing_debug_implementations, missing_docs)]
#[doc(hidden)]
pub struct Spawn {
inner: Box<Future<Item=Child, Error=io::Error>>,
}
#[deprecated(note = "use std::process::Command instead")]
#[allow(deprecated, missing_docs)]
#[doc(hidden)]
impl Command {
pub fn new<T: AsRef<OsStr>>(exe: T, handle: &Handle) -> Command {
Command::_new(exe.as_ref(), handle)
}
fn _new(exe: &OsStr, handle: &Handle) -> Command {
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
}
pub fn spawn(mut self) -> Spawn {
Spawn {
inner: Box::new(self.inner.spawn_async(&self.handle).into_future()),
}
}
}
#[deprecated(note = "use std::process::Command instead")]
#[allow(deprecated)]
#[doc(hidden)]
impl Future for Spawn {
type Item = Child;
type Error = io::Error;
fn poll(&mut self) -> Poll<Child, io::Error> {
self.inner.poll()
}
}