diff --git a/Cargo.toml b/Cargo.toml index 6ed88797e..705290815 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ futures = "0.1.11" mio = "0.6.5" tokio-core = "0.1.6" tokio-io = "0.1" +tokio-reactor = "0.1" [dev-dependencies] env_logger = { version = "0.4", default-features = false } @@ -43,4 +44,4 @@ features = [ [target.'cfg(unix)'.dependencies] libc = "0.2" -tokio-signal = "0.1" +tokio-signal = "0.2" diff --git a/src/lib.rs b/src/lib.rs index 8b84abfa8..0256ecd69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ //! // 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()); +//! .spawn_async_with_handle(core.handle().new_tokio_handle()); //! //! // Make sure our child succeeded in spawning //! let child = child.expect("failed to spawn"); @@ -62,7 +62,7 @@ //! // 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()); +//! .output_async_with_handle(core.handle().new_tokio_handle()); //! let output = core.run(output).expect("failed to collect output"); //! //! assert!(output.status.success()); @@ -100,7 +100,7 @@ //! let mut core = Core::new().unwrap(); //! let mut cmd = Command::new("cat"); //! let mut cat = cmd.stdout(Stdio::piped()); -//! let child = cat.spawn_async(&core.handle()).unwrap(); +//! let child = cat.spawn_async_with_handle(core.handle().new_tokio_handle()).unwrap(); //! core.run(print_lines(child)).unwrap(); //! } //! ``` @@ -122,6 +122,7 @@ extern crate futures; extern crate tokio_core; extern crate tokio_io; +extern crate tokio_reactor; extern crate mio; use std::io::{self, Read, Write}; @@ -130,9 +131,9 @@ use std::process::{self, ExitStatus, Output, Stdio}; use futures::{Future, Poll, IntoFuture}; use futures::future::{Either, ok}; use std::fmt; -use tokio_core::reactor::Handle; use tokio_io::io::{read_to_end}; use tokio_io::{AsyncWrite, AsyncRead, IoFuture}; +use tokio_reactor::Handle; #[path = "unix.rs"] #[cfg(unix)] @@ -154,6 +155,22 @@ mod imp; /// I/O handles created from this crate are all asynchronous as well (differing /// from their `std` counterparts). pub trait CommandExt { + /// Executes the command as a child process, returning a handle to it. + /// + /// By default, stdin, stdout and stderr are inherited from the parent. + /// + /// This method will spawn the child process synchronously and return a + /// handle to a future-aware child process. The `Child` returned implements + /// `Future` itself to acquire the `ExitStatus` of the child, and otherwise + /// the `Child` has methods to acquire handles to the stdin, stdout, and + /// stderr streams. + /// + /// All I/O this child does will be associated with the current default + /// event loop. + fn spawn_async(&mut self) -> io::Result { + self.spawn_async_with_handle(&Handle::default()) + } + /// Executes the command as a child process, returning a handle to it. /// /// By default, stdin, stdout and stderr are inherited from the parent. @@ -167,7 +184,32 @@ pub trait CommandExt { /// The `handle` specified to this method must be a handle to a valid event /// loop, and all I/O this child does will be associated with the specified /// event loop. - fn spawn_async(&mut self, handle: &Handle) -> io::Result; + fn spawn_async_with_handle(&mut self, handle: &Handle) -> io::Result; + + /// Executes a command as a child process, waiting for it to finish and + /// collecting its exit status. + /// + /// By default, stdin, stdout and stderr are inherited from the parent. + /// + /// The `StatusAsync` future returned will resolve to the `ExitStatus` + /// type in the standard library representing how the process exited. If + /// any input/output handles are set to a pipe then they will be immediately + /// closed after the child is spawned. + /// + /// All I/O this child does will be associated with the current default + /// event loop. + /// + /// If the `StatusAsync` future is dropped before the future resolves, then + /// the child will be killed, if it was spawned. + /// + /// # Errors + /// + /// This function will return an error immediately if the child process + /// cannot be spawned. Otherwise errors obtained while waiting for the child + /// are returned through the `StatusAsync` future. + fn status_async(&mut self) -> io::Result { + self.status_async_with_handle(&Handle::default()) + } /// Executes a command as a child process, waiting for it to finish and /// collecting its exit status. @@ -190,33 +232,30 @@ pub trait CommandExt { /// This function will return an error immediately if the child process /// cannot be spawned. Otherwise errors obtained while waiting for the child /// are returned through the `StatusAsync` future. - fn status_async(&mut self, handle: &Handle) -> io::Result; + fn status_async_with_handle(&mut self, handle: &Handle) -> io::Result; - /// Executes a command as a child process, waiting for it to finish and - /// collecting its exit status. + /// Executes the command as a child process, waiting for it to finish and + /// collecting all of its output. /// - /// By default, stdin, stdout and stderr are inherited from the parent. + /// > **Note**: this method, unlike the standard library, will + /// > unconditionally configure the stdout/stderr handles to be pipes, even + /// > if they have been previously configured. If this is not desired then + /// > the `spawn_async` method should be used in combination with the + /// > `wait_with_output` method on child. /// - /// The `StatusAsync` future returned will resolve to the `ExitStatus` - /// type in the standard library representing how the process exited. If - /// any input/output handles are set to a pipe then they will be immediately - /// closed after the child is spawned. + /// This method will return a future representing the collection of the + /// child process's stdout/stderr. The `OutputAsync` future will resolve to + /// the `Output` type in the standard library, containing `stdout` and + /// `stderr` as `Vec` along with an `ExitStatus` representing how the + /// process exited. /// - /// The `handle` specified must be a handle to a valid event loop, and all - /// I/O this child does will be associated with the specified event loop. + /// All I/O this child does will be associated with the current default + /// event loop. /// - /// If the `StatusAsync` future is dropped before the future resolves, then + /// If the `OutputAsync` future is dropped before the future resolves, then /// the child will be killed, if it was spawned. - /// - /// # Errors - /// - /// This function will return an error immediately if the child process - /// cannot be spawned. Otherwise errors obtained while waiting for the child - /// are returned through the `StatusAsync2` future. - #[doc(hidden)] - #[deprecated(note = "renamed to `status_async`", since = "0.2.1")] - fn status_async2(&mut self, handle: &Handle) -> io::Result { - self.status_async(handle) + fn output_async(&mut self) -> OutputAsync { + self.output_async_with_handle(&Handle::default()) } /// Executes the command as a child process, waiting for it to finish and @@ -239,12 +278,12 @@ pub trait CommandExt { /// /// If the `OutputAsync` future is dropped before the future resolves, then /// the child will be killed, if it was spawned. - fn output_async(&mut self, handle: &Handle) -> OutputAsync; + fn output_async_with_handle(&mut self, handle: &Handle) -> OutputAsync; } impl CommandExt for process::Command { - fn spawn_async(&mut self, handle: &Handle) -> io::Result { + fn spawn_async_with_handle(&mut self, handle: &Handle) -> io::Result { let mut child = Child { child: imp::Child::new(try!(self.spawn()), handle), stdin: None, @@ -264,8 +303,8 @@ impl CommandExt for process::Command { Ok(child) } - fn status_async(&mut self, handle: &Handle) -> io::Result { - self.spawn_async(handle).map(|mut child| { + fn status_async_with_handle(&mut self, handle: &Handle) -> io::Result { + self.spawn_async_with_handle(handle).map(|mut child| { // Ensure we close any stdio handles so we can't deadlock // waiting on the child which may be waiting to read/write // to a pipe we're holding. @@ -279,13 +318,16 @@ impl CommandExt for process::Command { }) } - fn output_async(&mut self, handle: &Handle) -> OutputAsync { + fn output_async_with_handle(&mut self, handle: &Handle) -> OutputAsync { self.stdout(Stdio::piped()); self.stderr(Stdio::piped()); + + let inner = self.spawn_async_with_handle(handle) + .into_future() + .and_then(|c| c.wait_with_output()); + OutputAsync { - inner: Box::new(self.spawn_async(handle).into_future().and_then(|c| { - c.wait_with_output() - })), + inner: Box::new(inner), } } } diff --git a/src/unix.rs b/src/unix.rs index 123e68602..7dcbe2ab0 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -37,7 +37,7 @@ use mio; use self::tokio_signal::unix::Signal; use std::fmt; use tokio_io::IoFuture; -use tokio_core::reactor::{Handle, PollEvented}; +use tokio_reactor::{Handle, PollEvented}; #[must_use = "futures do nothing unless polled"] pub struct Child { @@ -62,7 +62,7 @@ impl Child { Child { inner: inner, reaped: false, - sigchld: Signal::new(libc::SIGCHLD, handle).flatten_stream(), + sigchld: Signal::with_handle(libc::SIGCHLD, handle).flatten_stream(), } } @@ -224,6 +224,6 @@ fn stdio(option: Option, handle: &Handle) return Err(io::Error::last_os_error()) } } - let io = try!(PollEvented::new(Fd(io), handle)); + let io = try!(PollEvented::new_with_handle(Fd(io), handle)); Ok(Some(io)) } diff --git a/src/windows.rs b/src/windows.rs index d60d7b8de..83e57f457 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -36,7 +36,7 @@ use self::winapi::um::synchapi::*; use self::winapi::um::threadpoollegacyapiset::*; use self::winapi::um::winbase::*; use self::winapi::um::winnt::*; -use tokio_core::reactor::{PollEvented, Handle}; +use tokio_reactor::{Handle, PollEvented}; #[must_use = "futures do nothing unless polled"] pub struct Child { @@ -182,6 +182,6 @@ fn stdio(option: Option, handle: &Handle) None => return Ok(None), }; let pipe = unsafe { NamedPipe::from_raw_handle(io.into_raw_handle()) }; - let io = try!(PollEvented::new(pipe, handle)); + let io = try!(PollEvented::new_with_handle(pipe, handle)); Ok(Some(io)) } diff --git a/tests/smoke.rs b/tests/smoke.rs index 89f3e300b..69185bab9 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -11,7 +11,7 @@ fn simple() { let mut lp = Core::new().unwrap(); let mut cmd = support::cmd("exit"); cmd.arg("2"); - let mut child = cmd.spawn_async(&lp.handle()).unwrap(); + let mut child = cmd.spawn_async_with_handle(lp.handle().new_tokio_handle()).unwrap(); let id = child.id(); assert!(id > 0); let status = lp.run(&mut child).unwrap(); diff --git a/tests/stdio.rs b/tests/stdio.rs index dd8a96adf..6546cb44f 100644 --- a/tests/stdio.rs +++ b/tests/stdio.rs @@ -85,7 +85,7 @@ fn feed_cat(mut cat: Child, n: usize) -> Box