tokio-process 0.2.0

An implementation of an asynchronous process management backed futures.
tokio-process-0.2.0 has been yanked.

An implementation of asynchronous process management for Tokio.

This crate provides a CommandExt trait to enhance the functionality of the Command type in the standard library. The three methods provided by this trait mirror the "spawning" methods in the standard library. The CommandExt trait in this crate, though, returns "future aware" types that interoperate with Tokio. The asynchronous process support is provided through signal handling on Unix and system APIs on Windows.

Examples

Here's an example program which will spawn echo hello world and then wait for it using an event loop.

extern crate futures;
extern crate tokio_core;
extern crate tokio_process;

use std::process::Command;

use futures::Future;
use tokio_core::reactor::Core;
use tokio_process::CommandExt;

fn main() {
    // Create our own local event loop
    let mut core = Core::new().unwrap();

    // Use the standard library's `Command` type to build a process and
    // then execute it via the `CommandExt` trait.
    let child = Command::new("echo").arg("hello").arg("world")
                        .spawn_async(&core.handle());

    // Make sure our child succeeded in spawning
    let child = child.expect("failed to spawn");

    match core.run(child) {
        Ok(status) => println!("exit status: {}", status),
        Err(e) => panic!("failed to wait for exit: {}", e),
    }
}

Next, let's take a look at an example where we not only spawn echo hello world but we also capture its output.

extern crate futures;
extern crate tokio_core;
extern crate tokio_process;

use std::process::Command;

use futures::Future;
use tokio_core::reactor::Core;
use tokio_process::CommandExt;

fn main() {
    let mut core = Core::new().unwrap();

    // Like above, but use `output_async` which returns a future instead of
    // immediately returning the `Child`.
    let output = Command::new("echo").arg("hello").arg("world")
                        .output_async(&core.handle());
    let output = core.run(output).expect("failed to collect output");

    assert!(output.status.success());
    assert_eq!(output.stdout, b"hello world\n");
}

Caveats

While similar to the standard library, this crate's Child type differs importantly in the behavior of drop. In the standard library, a child process will continue running after the instance of std::process::Child is dropped. In this crate, however, because tokio_process::Child is a future of the child's ExitStatus, a child process is terminated if tokio_process::Child is dropped. The behavior of the standard library can be regained with the Child::forget method.

As a final caveat, currently this crate relies on the tokio-signal crate and therefore inherits its current restriction. Namely, once a child has been spawned onto an event loop then that event loop must stay alive for any spawned child in the future to make progress. In other words, once you spawn a child onto an event loop, you should ensure that the event loop keeps running for the duration of the program if there are multiple event loops. Unfortunately this makes testing particularly tricky, but you can work around this with an initial event loop that just runs forever in the background.