Files
rust/src/libstd/old_io/process.rs

1246 lines
42 KiB
Rust
Raw Normal View History

// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Bindings for executing child processes
2014-10-27 15:37:07 -07:00
#![allow(non_upper_case_globals)]
#![unstable(feature = "old_io")]
#![deprecated(since = "1.0.0",
reason = "replaced with the std::process module")]
pub use self::StdioContainer::*;
pub use self::ProcessExit::*;
use prelude::v1::*;
use collections::HashMap;
use ffi::CString;
use fmt;
use old_io::pipe::{PipeStream, PipePair};
use old_io::{IoResult, IoError, Reader, Writer};
use old_io;
use old_path::{Path, GenericPath};
use libc;
use os;
use old_path::BytesContainer;
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
use sync::mpsc::{channel, Receiver};
use sys::fs::FileDesc;
use sys::process::Process as ProcessImp;
use sys;
2015-02-17 15:10:25 -08:00
use thread;
std: Stabilize the std::hash module This commit aims to prepare the `std::hash` module for alpha by formalizing its current interface whileholding off on adding `#[stable]` to the new APIs. The current usage with the `HashMap` and `HashSet` types is also reconciled by separating out composable parts of the design. The primary goal of this slight redesign is to separate the concepts of a hasher's state from a hashing algorithm itself. The primary change of this commit is to separate the `Hasher` trait into a `Hasher` and a `HashState` trait. Conceptually the old `Hasher` trait was actually just a factory for various states, but hashing had very little control over how these states were used. Additionally the old `Hasher` trait was actually fairly unrelated to hashing. This commit redesigns the existing `Hasher` trait to match what the notion of a `Hasher` normally implies with the following definition: trait Hasher { type Output; fn reset(&mut self); fn finish(&self) -> Output; } This `Hasher` trait emphasizes that hashing algorithms may produce outputs other than a `u64`, so the output type is made generic. Other than that, however, very little is assumed about a particular hasher. It is left up to implementors to provide specific methods or trait implementations to feed data into a hasher. The corresponding `Hash` trait becomes: trait Hash<H: Hasher> { fn hash(&self, &mut H); } The old default of `SipState` was removed from this trait as it's not something that we're willing to stabilize until the end of time, but the type parameter is always required to implement `Hasher`. Note that the type parameter `H` remains on the trait to enable multidispatch for specialization of hashing for particular hashers. Note that `Writer` is not mentioned in either of `Hash` or `Hasher`, it is simply used as part `derive` and the implementations for all primitive types. With these definitions, the old `Hasher` trait is realized as a new `HashState` trait in the `collections::hash_state` module as an unstable addition for now. The current definition looks like: trait HashState { type Hasher: Hasher; fn hasher(&self) -> Hasher; } The purpose of this trait is to emphasize that the one piece of functionality for implementors is that new instances of `Hasher` can be created. This conceptually represents the two keys from which more instances of a `SipHasher` can be created, and a `HashState` is what's stored in a `HashMap`, not a `Hasher`. Implementors of custom hash algorithms should implement the `Hasher` trait, and only hash algorithms intended for use in hash maps need to implement or worry about the `HashState` trait. The entire module and `HashState` infrastructure remains `#[unstable]` due to it being recently redesigned, but some other stability decision made for the `std::hash` module are: * The `Writer` trait remains `#[experimental]` as it's intended to be replaced with an `io::Writer` (more details soon). * The top-level `hash` function is `#[unstable]` as it is intended to be generic over the hashing algorithm instead of hardwired to `SipHasher` * The inner `sip` module is now private as its one export, `SipHasher` is reexported in the `hash` module. And finally, a few changes were made to the default parameters on `HashMap`. * The `RandomSipHasher` default type parameter was renamed to `RandomState`. This renaming emphasizes that it is not a hasher, but rather just state to generate hashers. It also moves away from the name "sip" as it may not always be implemented as `SipHasher`. This type lives in the `std::collections::hash_map` module as `#[unstable]` * The associated `Hasher` type of `RandomState` is creatively called... `Hasher`! This concrete structure lives next to `RandomState` as an implemenation of the "default hashing algorithm" used for a `HashMap`. Under the hood this is currently implemented as `SipHasher`, but it draws an explicit interface for now and allows us to modify the implementation over time if necessary. There are many breaking changes outlined above, and as a result this commit is a: [breaking-change]
2014-12-09 12:37:23 -08:00
#[cfg(windows)] use hash;
#[cfg(windows)] use str;
/// Signal a process to exit, without forcibly killing it. Corresponds to
/// SIGTERM on unix platforms.
#[cfg(windows)] pub const PleaseExitSignal: isize = 15;
/// Signal a process to exit immediately, forcibly killing it. Corresponds to
/// SIGKILL on unix platforms.
#[cfg(windows)] pub const MustDieSignal: isize = 9;
/// Signal a process to exit, without forcibly killing it. Corresponds to
/// SIGTERM on unix platforms.
#[cfg(not(windows))] pub const PleaseExitSignal: isize = libc::SIGTERM as isize;
/// Signal a process to exit immediately, forcibly killing it. Corresponds to
/// SIGKILL on unix platforms.
#[cfg(not(windows))] pub const MustDieSignal: isize = libc::SIGKILL as isize;
2013-10-06 13:22:18 -07:00
/// Representation of a running or exited child process.
///
/// This structure is used to represent and manage child processes. A child
/// process is created via the `Command` struct, which configures the spawning
/// process and can itself be constructed using a builder-style interface.
///
/// # Examples
///
/// ```should_panic
2015-03-13 15:28:35 -07:00
/// # #![feature(old_io)]
/// use std::old_io::*;
///
/// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() {
/// Ok(child) => child,
/// Err(e) => panic!("failed to execute child: {}", e),
/// };
///
2014-08-18 17:52:38 -07:00
/// let contents = child.stdout.as_mut().unwrap().read_to_end();
/// assert!(child.wait().unwrap().success());
/// ```
pub struct Process {
handle: ProcessImp,
forget: bool,
/// None until wait() is called.
exit_code: Option<ProcessExit>,
/// Manually delivered signal
exit_signal: Option<isize>,
/// Deadline after which wait() will return
deadline: u64,
/// Handle to the child's stdin, if the `stdin` field of this process's
/// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
pub stdin: Option<PipeStream>,
/// Handle to the child's stdout, if the `stdout` field of this process's
/// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
pub stdout: Option<PipeStream>,
/// Handle to the child's stderr, if the `stderr` field of this process's
/// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
pub stderr: Option<PipeStream>,
}
2014-09-14 01:33:21 -07:00
/// A representation of environment variable name
/// It compares case-insensitive on Windows and case-sensitive everywhere else.
#[cfg(not(windows))]
2015-01-28 08:34:18 -05:00
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
2014-09-14 01:33:21 -07:00
struct EnvKey(CString);
#[doc(hidden)]
#[cfg(windows)]
2015-01-28 08:34:18 -05:00
#[derive(Eq, Clone, Debug)]
2014-09-14 01:33:21 -07:00
struct EnvKey(CString);
2015-02-19 18:35:52 -08:00
#[cfg(windows)]
impl hash::Hash for EnvKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
use ascii::AsciiExt;
let &EnvKey(ref x) = self;
match str::from_utf8(x.as_bytes()) {
Ok(s) => for ch in s.chars() {
ch.to_ascii_lowercase().hash(state);
},
Err(..) => x.hash(state)
}
}
}
2014-09-14 01:33:21 -07:00
#[cfg(windows)]
impl PartialEq for EnvKey {
fn eq(&self, other: &EnvKey) -> bool {
use ascii::AsciiExt;
2014-09-14 01:33:21 -07:00
let &EnvKey(ref x) = self;
let &EnvKey(ref y) = other;
match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) {
(Ok(xs), Ok(ys)) => {
2014-09-14 01:33:21 -07:00
if xs.len() != ys.len() {
return false
} else {
for (xch, ych) in xs.chars().zip(ys.chars()) {
if xch.to_ascii_lowercase() != ych.to_ascii_lowercase() {
2014-09-14 01:33:21 -07:00
return false;
}
}
return true;
}
},
// If either is not a valid utf8 string, just compare them byte-wise
_ => return x.eq(y)
}
}
}
impl BytesContainer for EnvKey {
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
let &EnvKey(ref k) = self;
k.container_as_bytes()
}
}
/// A HashMap representation of environment variables.
2014-09-14 01:33:21 -07:00
pub type EnvMap = HashMap<EnvKey, CString>;
/// The `Command` type acts as a process builder, providing fine-grained control
/// over how a new process should be spawned. A default configuration can be
/// generated using `Command::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:
///
/// ```
2015-03-13 15:28:35 -07:00
/// # #![feature(old_io)]
/// use std::old_io::*;
///
/// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
/// Ok(p) => p,
/// Err(e) => panic!("failed to execute process: {}", e),
/// };
///
2014-08-18 17:52:38 -07:00
/// let output = process.stdout.as_mut().unwrap().read_to_end();
/// ```
#[derive(Clone)]
pub struct Command {
// The internal data for the builder. Documented by the builder
// methods below, and serialized into rt::rtio::ProcessConfig.
program: CString,
args: Vec<CString>,
env: Option<EnvMap>,
cwd: Option<CString>,
stdin: StdioContainer,
stdout: StdioContainer,
stderr: StdioContainer,
uid: Option<usize>,
gid: Option<usize>,
detach: bool,
}
// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
// we cannot usefully take BytesContainer arguments by reference (without forcing an
// additional & around &str). So we are instead temporarily adding an instance
// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path
// instance should be removed, and arguments bound by BytesContainer should be passed by
// reference. (Here: {new, arg, args, env}.)
impl Command {
/// Constructs a new `Command` 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)
2014-05-22 22:50:31 +10:00
/// * A writeable pipe for stdout and stderr (file descriptors 1 and 2)
///
/// Builder methods are provided to change these defaults and
/// otherwise configure the process.
pub fn new<T: BytesContainer>(program: T) -> Command {
Command {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
program: CString::new(program.container_as_bytes()).unwrap(),
args: Vec::new(),
env: None,
cwd: None,
stdin: CreatePipe(true, false),
stdout: CreatePipe(false, true),
stderr: CreatePipe(false, true),
uid: None,
gid: None,
detach: false,
}
}
/// Add an argument to pass to the program.
pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
self.args.push(CString::new(arg.container_as_bytes()).unwrap());
self
}
/// Add multiple arguments to pass to the program.
pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command {
self.args.extend(args.iter().map(|arg| {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
CString::new(arg.container_as_bytes()).unwrap()
}));
self
}
// Get a mutable borrow of the environment variable map for this `Command`.
std: Add a new `env` module This is an implementation of [RFC 578][rfc] which adds a new `std::env` module to replace most of the functionality in the current `std::os` module. More details can be found in the RFC itself, but as a summary the following methods have all been deprecated: [rfc]: https://github.com/rust-lang/rfcs/pull/578 * `os::args_as_bytes` => `env::args` * `os::args` => `env::args` * `os::consts` => `env::consts` * `os::dll_filename` => no replacement, use `env::consts` directly * `os::page_size` => `env::page_size` * `os::make_absolute` => use `env::current_dir` + `join` instead * `os::getcwd` => `env::current_dir` * `os::change_dir` => `env::set_current_dir` * `os::homedir` => `env::home_dir` * `os::tmpdir` => `env::temp_dir` * `os::join_paths` => `env::join_paths` * `os::split_paths` => `env::split_paths` * `os::self_exe_name` => `env::current_exe` * `os::self_exe_path` => use `env::current_exe` + `pop` * `os::set_exit_status` => `env::set_exit_status` * `os::get_exit_status` => `env::get_exit_status` * `os::env` => `env::vars` * `os::env_as_bytes` => `env::vars` * `os::getenv` => `env::var` or `env::var_string` * `os::getenv_as_bytes` => `env::var` * `os::setenv` => `env::set_var` * `os::unsetenv` => `env::remove_var` Many function signatures have also been tweaked for various purposes, but the main changes were: * `Vec`-returning APIs now all return iterators instead * All APIs are now centered around `OsString` instead of `Vec<u8>` or `String`. There is currently on convenience API, `env::var_string`, which can be used to get the value of an environment variable as a unicode `String`. All old APIs are `#[deprecated]` in-place and will remain for some time to allow for migrations. The semantics of the APIs have been tweaked slightly with regard to dealing with invalid unicode (panic instead of replacement). The new `std::env` module is all contained within the `env` feature, so crates must add the following to access the new APIs: #![feature(env)] [breaking-change]
2015-01-27 12:20:58 -08:00
#[allow(deprecated)]
fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
match self.env {
Some(ref mut map) => map,
None => {
// if the env is currently just inheriting from the parent's,
// materialize the parent's env into a hashtable.
self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
(EnvKey(CString::new(k).unwrap()),
CString::new(v).unwrap())
}).collect());
self.env.as_mut().unwrap()
}
}
}
/// Inserts or updates an environment variable mapping.
2014-09-14 01:33:21 -07:00
///
/// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
/// and case-sensitive on all other platforms.
pub fn env<'a, T, U>(&'a mut self, key: T, val: U)
-> &'a mut Command
where T: BytesContainer, U: BytesContainer {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
let key = EnvKey(CString::new(key.container_as_bytes()).unwrap());
let val = CString::new(val.container_as_bytes()).unwrap();
self.get_env_map().insert(key, val);
self
}
/// Removes an environment variable mapping.
pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command
where T: BytesContainer {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
let key = EnvKey(CString::new(key.container_as_bytes()).unwrap());
self.get_env_map().remove(&key);
self
}
/// Sets the entire environment map for the child process.
///
/// If the given slice contains multiple instances of an environment
/// variable, the *rightmost* instance will determine the value.
pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)])
-> &'a mut Command
where T: BytesContainer, U: BytesContainer {
self.env = Some(env.iter().map(|&(ref k, ref v)| {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
(EnvKey(CString::new(k.container_as_bytes()).unwrap()),
CString::new(v.container_as_bytes()).unwrap())
}).collect());
self
}
/// Set the working directory for the child process.
pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
self.cwd = Some(CString::new(dir.as_vec()).unwrap());
self
}
/// Configuration for the child process's stdin handle (file descriptor 0).
/// Defaults to `CreatePipe(true, false)` so the input can be written to.
pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
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.
pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
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.
pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
self.stderr = 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.
pub fn uid<'a>(&'a mut self, id: usize) -> &'a mut Command {
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.
pub fn gid<'a>(&'a mut self, id: usize) -> &'a mut Command {
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.
pub fn detached<'a>(&'a mut self) -> &'a mut Command {
self.detach = true;
self
}
/// Executes the command as a child process, which is returned.
pub fn spawn(&self) -> IoResult<Process> {
let (their_stdin, our_stdin) = try!(setup_io(self.stdin));
let (their_stdout, our_stdout) = try!(setup_io(self.stdout));
let (their_stderr, our_stderr) = try!(setup_io(self.stderr));
match ProcessImp::spawn(self, their_stdin, their_stdout, their_stderr) {
Err(e) => Err(e),
Ok(handle) => Ok(Process {
handle: handle,
forget: false,
exit_code: None,
exit_signal: None,
deadline: 0,
stdin: our_stdin,
stdout: our_stdout,
stderr: our_stderr,
})
}
}
/// Executes the command as a child process, waiting for it to finish and
/// collecting all of its output.
///
/// # Examples
///
/// ```
2015-03-13 15:28:35 -07:00
/// # #![feature(old_io, core)]
/// use std::old_io::Command;
///
/// let output = match Command::new("cat").arg("foot.txt").output() {
/// Ok(output) => output,
/// Err(e) => panic!("failed to execute process: {}", e),
/// };
///
/// println!("status: {}", output.status);
2015-03-30 19:22:46 +03:00
/// println!("stdout: {}", String::from_utf8_lossy(output.output.as_ref()));
/// println!("stderr: {}", String::from_utf8_lossy(output.error.as_ref()));
/// ```
pub fn output(&self) -> IoResult<ProcessOutput> {
self.spawn().and_then(|p| p.wait_with_output())
}
/// Executes a command as a child process, waiting for it to finish and
/// collecting its exit status.
///
/// # Examples
///
/// ```
2015-03-13 15:28:35 -07:00
/// # #![feature(old_io)]
/// use std::old_io::Command;
///
/// let status = match Command::new("ls").status() {
/// Ok(status) => status,
/// Err(e) => panic!("failed to execute process: {}", e),
/// };
///
/// println!("process exited with: {}", status);
/// ```
pub fn status(&self) -> IoResult<ProcessExit> {
self.spawn().and_then(|mut p| p.wait())
}
}
std: Stabilize the std::fmt module This commit performs a final stabilization pass over the std::fmt module, marking all necessary APIs as stable. One of the more interesting aspects of this module is that it exposes a good deal of its runtime representation to the outside world in order for `format_args!` to be able to construct the format strings. Instead of hacking the compiler to assume that these items are stable, this commit instead lays out a story for the stabilization and evolution of these APIs. There are three primary details used by the `format_args!` macro: 1. `Arguments` - an opaque package of a "compiled format string". This structure is passed around and the `write` function is the source of truth for transforming a compiled format string into a string at runtime. This must be able to be constructed in stable code. 2. `Argument` - an opaque structure representing an argument to a format string. This is *almost* a trait object as it's just a pointer/function pair, but due to the function originating from one of many traits, it's not actually a trait object. Like `Arguments`, this must be constructed from stable code. 3. `fmt::rt` - this module contains the runtime type definitions primarily for the `rt::Argument` structure. Whenever an argument is formatted with nonstandard flags, a corresponding `rt::Argument` is generated describing how the argument is being formatted. This can be used to construct an `Arguments`. The primary interface to `std::fmt` is the `Arguments` structure, and as such this type name is stabilize as-is today. It is expected for libraries to pass around an `Arguments` structure to represent a pending formatted computation. The remaining portions are largely "cruft" which would rather not be stabilized, but due to the stability checks they must be. As a result, almost all pieces have been renamed to represent that they are "version 1" of the formatting representation. The theory is that at a later date if we change the representation of these types we can add new definitions called "version 2" and corresponding constructors for `Arguments`. One of the other remaining large questions about the fmt module were how the pending I/O reform would affect the signatures of methods in the module. Due to [RFC 526][rfc], however, the writers of fmt are now incompatible with the writers of io, so this question has largely been solved. As a result the interfaces are largely stabilized as-is today. [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md Specifically, the following changes were made: * The contents of `fmt::rt` were all moved under `fmt::rt::v1` * `fmt::rt` is stable * `fmt::rt::v1` is stable * `Error` is stable * `Writer` is stable * `Writer::write_str` is stable * `Writer::write_fmt` is stable * `Formatter` is stable * `Argument` has been renamed to `ArgumentV1` and is stable * `ArgumentV1::new` is stable * `ArgumentV1::from_uint` is stable * `Arguments::new_v1` is stable (renamed from `new`) * `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`) * All formatting traits are now stable, as well as the `fmt` method. * `fmt::write` is stable * `fmt::format` is stable * `Formatter::pad_integral` is stable * `Formatter::pad` is stable * `Formatter::write_str` is stable * `Formatter::write_fmt` is stable * Some assorted top level items which were only used by `format_args!` were removed in favor of static functions on `ArgumentV1` as well. * The formatting-flag-accessing methods remain unstable Within the contents of the `fmt::rt::v1` module, the following actions were taken: * Reexports of all enum variants were removed * All prefixes on enum variants were removed * A few miscellaneous enum variants were renamed * Otherwise all structs, fields, and variants were marked stable. In addition to these actions in the `std::fmt` module, many implementations of `Show` and `String` were stabilized as well. In some other modules: * `ToString` is now stable * `ToString::to_string` is now stable * `Vec` no longer implements `fmt::Writer` (this has moved to `String`) This is a breaking change due to all of the changes to the `fmt::rt` module, but this likely will not have much impact on existing programs. Closes #20661 [breaking-change]
2015-01-13 15:42:53 -08:00
#[stable(feature = "rust1", since = "1.0.0")]
std: Rename Show/String to Debug/Display This commit is an implementation of [RFC 565][rfc] which is a stabilization of the `std::fmt` module and the implementations of various formatting traits. Specifically, the following changes were performed: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0565-show-string-guidelines.md * The `Show` trait is now deprecated, it was renamed to `Debug` * The `String` trait is now deprecated, it was renamed to `Display` * Many `Debug` and `Display` implementations were audited in accordance with the RFC and audited implementations now have the `#[stable]` attribute * Integers and floats no longer print a suffix * Smart pointers no longer print details that they are a smart pointer * Paths with `Debug` are now quoted and escape characters * The `unwrap` methods on `Result` now require `Display` instead of `Debug` * The `Error` trait no longer has a `detail` method and now requires that `Display` must be implemented. With the loss of `String`, this has moved into libcore. * `impl<E: Error> FromError<E> for Box<Error>` now exists * `derive(Show)` has been renamed to `derive(Debug)`. This is not currently warned about due to warnings being emitted on stage1+ While backwards compatibility is attempted to be maintained with a blanket implementation of `Display` for the old `String` trait (and the same for `Show`/`Debug`) this is still a breaking change due to primitives no longer implementing `String` as well as modifications such as `unwrap` and the `Error` trait. Most code is fairly straightforward to update with a rename or tweaks of method calls. [breaking-change] Closes #21436
2015-01-20 15:45:07 -08:00
impl fmt::Debug for Command {
/// Format the program and arguments of a Command for display. Any
/// non-utf8 data is lossily converted using the utf8 replacement
/// character.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
std: Stabilize the std::fmt module This commit performs a final stabilization pass over the std::fmt module, marking all necessary APIs as stable. One of the more interesting aspects of this module is that it exposes a good deal of its runtime representation to the outside world in order for `format_args!` to be able to construct the format strings. Instead of hacking the compiler to assume that these items are stable, this commit instead lays out a story for the stabilization and evolution of these APIs. There are three primary details used by the `format_args!` macro: 1. `Arguments` - an opaque package of a "compiled format string". This structure is passed around and the `write` function is the source of truth for transforming a compiled format string into a string at runtime. This must be able to be constructed in stable code. 2. `Argument` - an opaque structure representing an argument to a format string. This is *almost* a trait object as it's just a pointer/function pair, but due to the function originating from one of many traits, it's not actually a trait object. Like `Arguments`, this must be constructed from stable code. 3. `fmt::rt` - this module contains the runtime type definitions primarily for the `rt::Argument` structure. Whenever an argument is formatted with nonstandard flags, a corresponding `rt::Argument` is generated describing how the argument is being formatted. This can be used to construct an `Arguments`. The primary interface to `std::fmt` is the `Arguments` structure, and as such this type name is stabilize as-is today. It is expected for libraries to pass around an `Arguments` structure to represent a pending formatted computation. The remaining portions are largely "cruft" which would rather not be stabilized, but due to the stability checks they must be. As a result, almost all pieces have been renamed to represent that they are "version 1" of the formatting representation. The theory is that at a later date if we change the representation of these types we can add new definitions called "version 2" and corresponding constructors for `Arguments`. One of the other remaining large questions about the fmt module were how the pending I/O reform would affect the signatures of methods in the module. Due to [RFC 526][rfc], however, the writers of fmt are now incompatible with the writers of io, so this question has largely been solved. As a result the interfaces are largely stabilized as-is today. [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md Specifically, the following changes were made: * The contents of `fmt::rt` were all moved under `fmt::rt::v1` * `fmt::rt` is stable * `fmt::rt::v1` is stable * `Error` is stable * `Writer` is stable * `Writer::write_str` is stable * `Writer::write_fmt` is stable * `Formatter` is stable * `Argument` has been renamed to `ArgumentV1` and is stable * `ArgumentV1::new` is stable * `ArgumentV1::from_uint` is stable * `Arguments::new_v1` is stable (renamed from `new`) * `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`) * All formatting traits are now stable, as well as the `fmt` method. * `fmt::write` is stable * `fmt::format` is stable * `Formatter::pad_integral` is stable * `Formatter::pad` is stable * `Formatter::write_str` is stable * `Formatter::write_fmt` is stable * Some assorted top level items which were only used by `format_args!` were removed in favor of static functions on `ArgumentV1` as well. * The formatting-flag-accessing methods remain unstable Within the contents of the `fmt::rt::v1` module, the following actions were taken: * Reexports of all enum variants were removed * All prefixes on enum variants were removed * A few miscellaneous enum variants were renamed * Otherwise all structs, fields, and variants were marked stable. In addition to these actions in the `std::fmt` module, many implementations of `Show` and `String` were stabilized as well. In some other modules: * `ToString` is now stable * `ToString::to_string` is now stable * `Vec` no longer implements `fmt::Writer` (this has moved to `String`) This is a breaking change due to all of the changes to the `fmt::rt` module, but this likely will not have much impact on existing programs. Closes #20661 [breaking-change]
2015-01-13 15:42:53 -08:00
try!(write!(f, "{:?}", self.program));
2015-01-31 12:20:46 -05:00
for arg in &self.args {
std: Stabilize the std::fmt module This commit performs a final stabilization pass over the std::fmt module, marking all necessary APIs as stable. One of the more interesting aspects of this module is that it exposes a good deal of its runtime representation to the outside world in order for `format_args!` to be able to construct the format strings. Instead of hacking the compiler to assume that these items are stable, this commit instead lays out a story for the stabilization and evolution of these APIs. There are three primary details used by the `format_args!` macro: 1. `Arguments` - an opaque package of a "compiled format string". This structure is passed around and the `write` function is the source of truth for transforming a compiled format string into a string at runtime. This must be able to be constructed in stable code. 2. `Argument` - an opaque structure representing an argument to a format string. This is *almost* a trait object as it's just a pointer/function pair, but due to the function originating from one of many traits, it's not actually a trait object. Like `Arguments`, this must be constructed from stable code. 3. `fmt::rt` - this module contains the runtime type definitions primarily for the `rt::Argument` structure. Whenever an argument is formatted with nonstandard flags, a corresponding `rt::Argument` is generated describing how the argument is being formatted. This can be used to construct an `Arguments`. The primary interface to `std::fmt` is the `Arguments` structure, and as such this type name is stabilize as-is today. It is expected for libraries to pass around an `Arguments` structure to represent a pending formatted computation. The remaining portions are largely "cruft" which would rather not be stabilized, but due to the stability checks they must be. As a result, almost all pieces have been renamed to represent that they are "version 1" of the formatting representation. The theory is that at a later date if we change the representation of these types we can add new definitions called "version 2" and corresponding constructors for `Arguments`. One of the other remaining large questions about the fmt module were how the pending I/O reform would affect the signatures of methods in the module. Due to [RFC 526][rfc], however, the writers of fmt are now incompatible with the writers of io, so this question has largely been solved. As a result the interfaces are largely stabilized as-is today. [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md Specifically, the following changes were made: * The contents of `fmt::rt` were all moved under `fmt::rt::v1` * `fmt::rt` is stable * `fmt::rt::v1` is stable * `Error` is stable * `Writer` is stable * `Writer::write_str` is stable * `Writer::write_fmt` is stable * `Formatter` is stable * `Argument` has been renamed to `ArgumentV1` and is stable * `ArgumentV1::new` is stable * `ArgumentV1::from_uint` is stable * `Arguments::new_v1` is stable (renamed from `new`) * `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`) * All formatting traits are now stable, as well as the `fmt` method. * `fmt::write` is stable * `fmt::format` is stable * `Formatter::pad_integral` is stable * `Formatter::pad` is stable * `Formatter::write_str` is stable * `Formatter::write_fmt` is stable * Some assorted top level items which were only used by `format_args!` were removed in favor of static functions on `ArgumentV1` as well. * The formatting-flag-accessing methods remain unstable Within the contents of the `fmt::rt::v1` module, the following actions were taken: * Reexports of all enum variants were removed * All prefixes on enum variants were removed * A few miscellaneous enum variants were renamed * Otherwise all structs, fields, and variants were marked stable. In addition to these actions in the `std::fmt` module, many implementations of `Show` and `String` were stabilized as well. In some other modules: * `ToString` is now stable * `ToString::to_string` is now stable * `Vec` no longer implements `fmt::Writer` (this has moved to `String`) This is a breaking change due to all of the changes to the `fmt::rt` module, but this likely will not have much impact on existing programs. Closes #20661 [breaking-change]
2015-01-13 15:42:53 -08:00
try!(write!(f, " '{:?}'", arg));
}
Ok(())
}
}
fn setup_io(io: StdioContainer) -> IoResult<(Option<PipeStream>, Option<PipeStream>)> {
let ours;
let theirs;
match io {
Ignored => {
theirs = None;
ours = None;
}
InheritFd(fd) => {
theirs = Some(PipeStream::from_filedesc(FileDesc::new(fd, false)));
ours = None;
}
CreatePipe(readable, _writable) => {
let PipePair { reader, writer } = try!(PipeStream::pair());
if readable {
theirs = Some(reader);
ours = Some(writer);
} else {
theirs = Some(writer);
ours = Some(reader);
}
}
}
Ok((theirs, ours))
}
// Allow the sys module to get access to the Command state
impl sys::process::ProcessConfig<EnvKey, CString> for Command {
fn program(&self) -> &CString {
&self.program
}
fn args(&self) -> &[CString] {
&self.args
}
fn env(&self) -> Option<&EnvMap> {
self.env.as_ref()
}
fn cwd(&self) -> Option<&CString> {
self.cwd.as_ref()
}
fn uid(&self) -> Option<usize> {
self.uid.clone()
}
fn gid(&self) -> Option<usize> {
self.gid.clone()
}
fn detach(&self) -> bool {
self.detach
}
}
/// The output of a finished process.
#[derive(PartialEq, Eq, Clone)]
pub struct ProcessOutput {
/// The status (exit code) of the process.
2014-03-27 15:09:47 -07:00
pub status: ProcessExit,
/// The data that the process wrote to stdout.
pub output: Vec<u8>,
/// The data that the process wrote to stderr.
pub error: Vec<u8>,
}
/// Describes what to do with a standard io stream for a child process.
#[derive(Clone, Copy)]
pub enum StdioContainer {
/// This stream will be ignored. This is the equivalent of attaching the
/// stream to `/dev/null`
Ignored,
/// The specified file descriptor is inherited for the stream which it is
/// specified for. Ownership of the file descriptor is *not* taken, so the
/// caller must clean it up.
InheritFd(libc::c_int),
/// Creates a pipe for the specified file descriptor which will be created
/// when the process is spawned.
///
/// The first boolean argument is whether the pipe is readable, and the
/// second is whether it is writable. These properties are from the view of
/// the *child* process, not the parent process.
CreatePipe(bool /* readable */, bool /* writable */),
}
/// Describes the result of a process after it has terminated.
/// Note that Windows have no signals, so the result is usually ExitStatus.
2015-01-28 08:34:18 -05:00
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ProcessExit {
/// Normal termination with an exit status.
ExitStatus(isize),
/// Termination by signal, with the signal number.
ExitSignal(isize),
}
#[stable(feature = "rust1", since = "1.0.0")]
std: Rename Show/String to Debug/Display This commit is an implementation of [RFC 565][rfc] which is a stabilization of the `std::fmt` module and the implementations of various formatting traits. Specifically, the following changes were performed: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0565-show-string-guidelines.md * The `Show` trait is now deprecated, it was renamed to `Debug` * The `String` trait is now deprecated, it was renamed to `Display` * Many `Debug` and `Display` implementations were audited in accordance with the RFC and audited implementations now have the `#[stable]` attribute * Integers and floats no longer print a suffix * Smart pointers no longer print details that they are a smart pointer * Paths with `Debug` are now quoted and escape characters * The `unwrap` methods on `Result` now require `Display` instead of `Debug` * The `Error` trait no longer has a `detail` method and now requires that `Display` must be implemented. With the loss of `String`, this has moved into libcore. * `impl<E: Error> FromError<E> for Box<Error>` now exists * `derive(Show)` has been renamed to `derive(Debug)`. This is not currently warned about due to warnings being emitted on stage1+ While backwards compatibility is attempted to be maintained with a blanket implementation of `Display` for the old `String` trait (and the same for `Show`/`Debug`) this is still a breaking change due to primitives no longer implementing `String` as well as modifications such as `unwrap` and the `Error` trait. Most code is fairly straightforward to update with a rename or tweaks of method calls. [breaking-change] Closes #21436
2015-01-20 15:45:07 -08:00
impl fmt::Display for ProcessExit {
/// Format a ProcessExit enum, to nicely present the information.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ExitStatus(code) => write!(f, "exit code: {}", code),
ExitSignal(code) => write!(f, "signal: {}", code),
}
}
}
impl ProcessExit {
/// Was termination successful? Signal termination not considered a success,
/// and success is defined as a zero exit status.
pub fn success(&self) -> bool {
return self.matches_exit_status(0);
}
/// Checks whether this ProcessExit matches the given exit status.
/// Termination by signal will never match an exit code.
pub fn matches_exit_status(&self, wanted: isize) -> bool {
*self == ExitStatus(wanted)
}
}
impl Process {
/// Sends `signal` to another process in the system identified by `id`.
///
/// Note that windows doesn't quite have the same model as unix, so some
/// unix signals are mapped to windows signals. Notably, unix termination
/// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
///
/// Additionally, a signal number of 0 can check for existence of the target
/// process. Note, though, that on some platforms signals will continue to
/// be successfully delivered if the child has exited, but not yet been
/// reaped.
pub fn kill(id: libc::pid_t, signal: isize) -> IoResult<()> {
unsafe { ProcessImp::killpid(id, signal) }
}
/// Returns the process id of this child process
pub fn id(&self) -> libc::pid_t { self.handle.id() }
/// Sends the specified signal to the child process, returning whether the
/// signal could be delivered or not.
///
/// Note that signal 0 is interpreted as a poll to check whether the child
/// process is still alive or not. If an error is returned, then the child
/// process has exited.
///
/// On some unix platforms signals will continue to be received after a
/// child has exited but not yet been reaped. In order to report the status
/// of signal delivery correctly, unix implementations may invoke
/// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
///
/// # Errors
///
/// If the signal delivery fails, the corresponding error is returned.
pub fn signal(&mut self, signal: isize) -> IoResult<()> {
#[cfg(unix)] fn collect_status(p: &mut Process) {
// On Linux (and possibly other unices), a process that has exited will
// continue to accept signals because it is "defunct". The delivery of
// signals will only fail once the child has been reaped. For this
// reason, if the process hasn't exited yet, then we attempt to collect
// their status with WNOHANG.
if p.exit_code.is_none() {
match p.handle.try_wait() {
Some(code) => { p.exit_code = Some(code); }
None => {}
}
}
}
#[cfg(windows)] fn collect_status(_p: &mut Process) {}
collect_status(self);
// if the process has finished, and therefore had waitpid called,
// and we kill it, then on unix we might ending up killing a
// newer process that happens to have the same (re-used) id
if self.exit_code.is_some() {
return Err(IoError {
kind: old_io::InvalidInput,
desc: "invalid argument: can't kill an exited process",
detail: None,
})
}
// A successfully delivered signal that isn't 0 (just a poll for being
// alive) is recorded for windows (see wait())
match unsafe { self.handle.kill(signal) } {
Ok(()) if signal == 0 => Ok(()),
Ok(()) => { self.exit_signal = Some(signal); Ok(()) }
Err(e) => Err(e),
}
}
/// Sends a signal to this child requesting that it exits. This is
/// equivalent to sending a SIGTERM on unix platforms.
pub fn signal_exit(&mut self) -> IoResult<()> {
self.signal(PleaseExitSignal)
}
/// Sends a signal to this child forcing it to exit. This is equivalent to
/// sending a SIGKILL on unix platforms.
pub fn signal_kill(&mut self) -> IoResult<()> {
self.signal(MustDieSignal)
}
/// Wait for the child to exit completely, returning the status that it
/// exited with. This function will continue to have the same return value
/// after it has been called at least once.
///
/// The stdin handle to the child process will be closed before waiting.
///
/// # Errors
///
/// This function can fail if a timeout was previously specified via
/// `set_timeout` and the timeout expires before the child exits.
pub fn wait(&mut self) -> IoResult<ProcessExit> {
drop(self.stdin.take());
match self.exit_code {
Some(code) => Ok(code),
None => {
let code = try!(self.handle.wait(self.deadline));
// On windows, waitpid will never return a signal. If a signal
// was successfully delivered to the process, however, we can
// consider it as having died via a signal.
let code = match self.exit_signal {
None => code,
Some(signal) if cfg!(windows) => ExitSignal(signal),
Some(..) => code,
};
self.exit_code = Some(code);
Ok(code)
}
2014-06-03 20:09:39 -07:00
}
}
/// Sets a timeout, in milliseconds, for future calls to wait().
///
/// The argument specified is a relative distance into the future, in
/// milliseconds, after which any call to wait() will return immediately
/// with a timeout error, and all future calls to wait() will not block.
///
/// A value of `None` will clear any previous timeout, and a value of `Some`
/// will override any previously set timeout.
///
/// # Examples
///
/// ```no_run
2015-03-13 15:28:35 -07:00
/// # #![feature(old_io, io)]
/// use std::old_io::{Command, IoResult};
/// use std::old_io::process::ProcessExit;
///
/// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
/// let mut p = try!(Command::new("long-running-process").spawn());
///
/// // give the process 10 seconds to finish completely
/// p.set_timeout(Some(10_000));
/// match p.wait() {
/// Ok(status) => return Ok(status),
/// Err(..) => {}
/// }
///
/// // Attempt to exit gracefully, but don't wait for it too long
/// try!(p.signal_exit());
/// p.set_timeout(Some(1_000));
/// match p.wait() {
/// Ok(status) => return Ok(status),
/// Err(..) => {}
/// }
///
/// // Well, we did our best, forcefully kill the process
/// try!(p.signal_kill());
/// p.set_timeout(None);
/// p.wait()
/// }
/// ```
#[unstable(feature = "io",
reason = "the type of the timeout is likely to change")]
pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
self.deadline = timeout_ms.map(|i| i + sys::timer::now()).unwrap_or(0);
}
/// Simultaneously wait for the child to exit and collect all remaining
/// output on the stdout/stderr handles, returning a `ProcessOutput`
/// instance.
///
/// The stdin handle to the child is closed before waiting.
///
/// # Errors
///
/// This function can fail for any of the same reasons that `wait()` can
/// fail.
pub fn wait_with_output(mut self) -> IoResult<ProcessOutput> {
drop(self.stdin.take());
fn read(stream: Option<old_io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
let (tx, rx) = channel();
match stream {
2014-12-06 18:34:37 -08:00
Some(stream) => {
2015-02-17 15:10:25 -08:00
thread::spawn(move || {
2014-12-06 18:34:37 -08:00
let mut stream = stream;
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
tx.send(stream.read_to_end()).unwrap();
2015-01-05 21:59:45 -08:00
});
2014-12-06 18:34:37 -08:00
}
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
None => tx.send(Ok(Vec::new())).unwrap()
}
rx
}
let stdout = read(self.stdout.take());
let stderr = read(self.stderr.take());
let status = try!(self.wait());
Ok(ProcessOutput {
status: status,
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
output: stdout.recv().unwrap().unwrap_or(Vec::new()),
error: stderr.recv().unwrap().unwrap_or(Vec::new()),
})
}
/// Forgets this process, allowing it to outlive the parent
///
/// This function will forcefully prevent calling `wait()` on the child
/// process in the destructor, allowing the child to outlive the
/// parent. Note that this operation can easily lead to leaking the
/// resources of the child process, so care must be taken when
/// invoking this method.
pub fn forget(mut self) {
self.forget = true;
}
}
impl Drop for Process {
fn drop(&mut self) {
if self.forget { return }
// Close all I/O before exiting to ensure that the child doesn't wait
// forever to print some text or something similar.
drop(self.stdin.take());
drop(self.stdout.take());
drop(self.stderr.take());
self.set_timeout(None);
let _ = self.wait().unwrap();
}
}
#[cfg(test)]
mod tests {
use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound};
use old_io::{Reader, Writer};
use prelude::v1::{Ok, Err, drop, Some, None, Vec};
use prelude::v1::{String, Clone};
use prelude::v1::{Str, AsSlice, ToString};
use old_path::{GenericPath, Path};
use old_io::fs::PathExtensions;
use old_io::timer::*;
use rt::running_on_valgrind;
use str;
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
use super::{CreatePipe};
use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput};
use sync::mpsc::channel;
2015-02-17 15:10:25 -08:00
use thread;
use time::Duration;
// FIXME(#10380) these tests should not all be ignored on android.
#[cfg(not(target_os="android"))]
#[test]
fn smoke() {
let p = Command::new("true").spawn();
2014-01-30 14:10:53 -08:00
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().success());
}
#[cfg(not(target_os="android"))]
#[test]
fn smoke_failure() {
match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
Ok(..) => panic!(),
Err(..) => {}
}
}
#[cfg(not(target_os="android"))]
#[test]
fn exit_reported_right() {
let p = Command::new("false").spawn();
2014-01-30 14:10:53 -08:00
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().unwrap().matches_exit_status(1));
drop(p.wait().clone());
}
2014-09-28 22:31:50 -07:00
#[cfg(all(unix, not(target_os="android")))]
#[test]
fn signal_reported_right() {
let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn();
2014-01-30 14:10:53 -08:00
assert!(p.is_ok());
let mut p = p.unwrap();
match p.wait().unwrap() {
process::ExitSignal(9) => {},
result => panic!("not terminated by signal 9 (instead, {})", result),
}
}
pub fn read_all(input: &mut Reader) -> String {
input.read_to_string().unwrap()
}
pub fn run_output(cmd: Command) -> String {
let p = cmd.spawn();
2014-01-30 14:10:53 -08:00
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.stdout.is_some());
Clean up rustc warnings. compiletest: compact "linux" "macos" etc.as "unix". liballoc: remove a superfluous "use". libcollections: remove invocations of deprecated methods in favor of their suggested replacements and use "_" for a loop counter. libcoretest: remove invocations of deprecated methods; also add "allow(deprecated)" for testing a deprecated method itself. libglob: use "cfg_attr". libgraphviz: add a test for one of data constructors. libgreen: remove a superfluous "use". libnum: "allow(type_overflow)" for type cast into u8 in a test code. librustc: names of static variables should be in upper case. libserialize: v[i] instead of get(). libstd/ascii: to_lowercase() instead of to_lower(). libstd/bitflags: modify AnotherSetOfFlags to use i8 as its backend. It will serve better for testing various aspects of bitflags!. libstd/collections: "allow(deprecated)" for testing a deprecated method itself. libstd/io: remove invocations of deprecated methods and superfluous "use". Also add #[test] where it was missing. libstd/num: introduce a helper function to effectively remove invocations of a deprecated method. libstd/path and rand: remove invocations of deprecated methods and superfluous "use". libstd/task and libsync/comm: "allow(deprecated)" for testing a deprecated method itself. libsync/deque: remove superfluous "unsafe". libsync/mutex and once: names of static variables should be in upper case. libterm: introduce a helper function to effectively remove invocations of a deprecated method. We still see a few warnings about using obsoleted native::task::spawn() in the test modules for libsync. I'm not sure how I should replace them with std::task::TaksBuilder and native::task::NativeTaskBuilder (dependency to libstd?) Signed-off-by: NODA, Kai <nodakai@gmail.com>
2014-10-05 18:11:17 +08:00
let ret = read_all(p.stdout.as_mut().unwrap() as &mut Reader);
assert!(p.wait().unwrap().success());
return ret;
}
#[cfg(not(target_os="android"))]
#[test]
fn stdout_works() {
let mut cmd = Command::new("echo");
cmd.arg("foobar").stdout(CreatePipe(false, true));
assert_eq!(run_output(cmd), "foobar\n");
}
2014-09-28 22:31:50 -07:00
#[cfg(all(unix, not(target_os="android")))]
#[test]
fn set_cwd_works() {
let mut cmd = Command::new("/bin/sh");
cmd.arg("-c").arg("pwd")
.cwd(&Path::new("/"))
.stdout(CreatePipe(false, true));
assert_eq!(run_output(cmd), "/\n");
}
2014-09-28 22:31:50 -07:00
#[cfg(all(unix, not(target_os="android")))]
#[test]
fn stdin_works() {
let mut p = Command::new("/bin/sh")
.arg("-c").arg("read line; echo $line")
.stdin(CreatePipe(true, false))
.stdout(CreatePipe(false, true))
.spawn().unwrap();
Clean up rustc warnings. compiletest: compact "linux" "macos" etc.as "unix". liballoc: remove a superfluous "use". libcollections: remove invocations of deprecated methods in favor of their suggested replacements and use "_" for a loop counter. libcoretest: remove invocations of deprecated methods; also add "allow(deprecated)" for testing a deprecated method itself. libglob: use "cfg_attr". libgraphviz: add a test for one of data constructors. libgreen: remove a superfluous "use". libnum: "allow(type_overflow)" for type cast into u8 in a test code. librustc: names of static variables should be in upper case. libserialize: v[i] instead of get(). libstd/ascii: to_lowercase() instead of to_lower(). libstd/bitflags: modify AnotherSetOfFlags to use i8 as its backend. It will serve better for testing various aspects of bitflags!. libstd/collections: "allow(deprecated)" for testing a deprecated method itself. libstd/io: remove invocations of deprecated methods and superfluous "use". Also add #[test] where it was missing. libstd/num: introduce a helper function to effectively remove invocations of a deprecated method. libstd/path and rand: remove invocations of deprecated methods and superfluous "use". libstd/task and libsync/comm: "allow(deprecated)" for testing a deprecated method itself. libsync/deque: remove superfluous "unsafe". libsync/mutex and once: names of static variables should be in upper case. libterm: introduce a helper function to effectively remove invocations of a deprecated method. We still see a few warnings about using obsoleted native::task::spawn() in the test modules for libsync. I'm not sure how I should replace them with std::task::TaksBuilder and native::task::NativeTaskBuilder (dependency to libstd?) Signed-off-by: NODA, Kai <nodakai@gmail.com>
2014-10-05 18:11:17 +08:00
p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
drop(p.stdin.take());
Clean up rustc warnings. compiletest: compact "linux" "macos" etc.as "unix". liballoc: remove a superfluous "use". libcollections: remove invocations of deprecated methods in favor of their suggested replacements and use "_" for a loop counter. libcoretest: remove invocations of deprecated methods; also add "allow(deprecated)" for testing a deprecated method itself. libglob: use "cfg_attr". libgraphviz: add a test for one of data constructors. libgreen: remove a superfluous "use". libnum: "allow(type_overflow)" for type cast into u8 in a test code. librustc: names of static variables should be in upper case. libserialize: v[i] instead of get(). libstd/ascii: to_lowercase() instead of to_lower(). libstd/bitflags: modify AnotherSetOfFlags to use i8 as its backend. It will serve better for testing various aspects of bitflags!. libstd/collections: "allow(deprecated)" for testing a deprecated method itself. libstd/io: remove invocations of deprecated methods and superfluous "use". Also add #[test] where it was missing. libstd/num: introduce a helper function to effectively remove invocations of a deprecated method. libstd/path and rand: remove invocations of deprecated methods and superfluous "use". libstd/task and libsync/comm: "allow(deprecated)" for testing a deprecated method itself. libsync/deque: remove superfluous "unsafe". libsync/mutex and once: names of static variables should be in upper case. libterm: introduce a helper function to effectively remove invocations of a deprecated method. We still see a few warnings about using obsoleted native::task::spawn() in the test modules for libsync. I'm not sure how I should replace them with std::task::TaksBuilder and native::task::NativeTaskBuilder (dependency to libstd?) Signed-off-by: NODA, Kai <nodakai@gmail.com>
2014-10-05 18:11:17 +08:00
let out = read_all(p.stdout.as_mut().unwrap() as &mut Reader);
assert!(p.wait().unwrap().success());
assert_eq!(out, "foobar\n");
}
#[cfg(not(target_os="android"))]
#[test]
fn detach_works() {
let mut p = Command::new("true").detached().spawn().unwrap();
assert!(p.wait().unwrap().success());
}
#[cfg(windows)]
#[test]
fn uid_fails_on_windows() {
assert!(Command::new("test").uid(10).spawn().is_err());
}
2014-09-28 22:31:50 -07:00
#[cfg(all(unix, not(target_os="android")))]
#[test]
fn uid_works() {
use libc;
let mut p = Command::new("/bin/sh")
.arg("-c").arg("true")
.uid(unsafe { libc::getuid() as usize })
.gid(unsafe { libc::getgid() as usize })
.spawn().unwrap();
assert!(p.wait().unwrap().success());
}
2014-09-28 22:31:50 -07:00
#[cfg(all(unix, not(target_os="android")))]
#[test]
fn uid_to_root_fails() {
use libc;
// if we're already root, this isn't a valid test. Most of the bots run
// as non-root though (android is an exception).
if unsafe { libc::getuid() == 0 } { return }
assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
}
#[cfg(not(target_os="android"))]
#[test]
fn test_process_status() {
let mut status = Command::new("false").status().unwrap();
assert!(status.matches_exit_status(1));
status = Command::new("true").status().unwrap();
assert!(status.success());
}
#[test]
fn test_process_output_fail_to_start() {
match Command::new("/no-binary-by-this-name-should-exist").output() {
Err(e) => assert_eq!(e.kind, FileNotFound),
Ok(..) => panic!()
}
}
#[cfg(not(target_os="android"))]
#[test]
fn test_process_output_output() {
let ProcessOutput {status, output, error}
= Command::new("echo").arg("hello").output().unwrap();
let output_str = str::from_utf8(&output).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
// FIXME #7224
if !running_on_valgrind() {
assert_eq!(error, Vec::new());
}
}
#[cfg(not(target_os="android"))]
#[test]
fn test_process_output_error() {
let ProcessOutput {status, output, error}
= Command::new("mkdir").arg(".").output().unwrap();
assert!(status.matches_exit_status(1));
assert_eq!(output, Vec::new());
assert!(!error.is_empty());
}
#[cfg(not(target_os="android"))]
#[test]
fn test_finish_once() {
let mut prog = Command::new("false").spawn().unwrap();
assert!(prog.wait().unwrap().matches_exit_status(1));
}
#[cfg(not(target_os="android"))]
#[test]
fn test_finish_twice() {
let mut prog = Command::new("false").spawn().unwrap();
assert!(prog.wait().unwrap().matches_exit_status(1));
assert!(prog.wait().unwrap().matches_exit_status(1));
}
#[cfg(not(target_os="android"))]
#[test]
fn test_wait_with_output_once() {
let prog = Command::new("echo").arg("hello").spawn().unwrap();
let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap();
let output_str = str::from_utf8(&output).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_string(), "hello");
// FIXME #7224
if !running_on_valgrind() {
assert_eq!(error, Vec::new());
}
}
2014-09-28 22:31:50 -07:00
#[cfg(all(unix, not(target_os="android")))]
pub fn pwd_cmd() -> Command {
Command::new("pwd")
}
#[cfg(target_os="android")]
pub fn pwd_cmd() -> Command {
let mut cmd = Command::new("/system/bin/sh");
cmd.arg("-c").arg("pwd");
cmd
}
#[cfg(windows)]
pub fn pwd_cmd() -> Command {
let mut cmd = Command::new("cmd");
cmd.arg("/c").arg("cd");
cmd
}
#[test]
fn test_keep_current_working_dir() {
use os;
let prog = pwd_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
let parent_dir = os::getcwd().unwrap();
let child_dir = Path::new(output.trim());
let parent_stat = parent_dir.stat().unwrap();
let child_stat = child_dir.stat().unwrap();
assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
}
#[test]
fn test_change_working_directory() {
use os;
// test changing to the parent of os::getcwd() because we know
// the path exists (and os::getcwd() is not expected to be root)
let parent_dir = os::getcwd().unwrap().dir_path();
let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
let child_dir = Path::new(output.trim());
let parent_stat = parent_dir.stat().unwrap();
let child_stat = child_dir.stat().unwrap();
assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
}
2014-09-28 22:31:50 -07:00
#[cfg(all(unix, not(target_os="android")))]
pub fn env_cmd() -> Command {
Command::new("env")
}
#[cfg(target_os="android")]
pub fn env_cmd() -> Command {
let mut cmd = Command::new("/system/bin/sh");
cmd.arg("-c").arg("set");
cmd
}
#[cfg(windows)]
pub fn env_cmd() -> Command {
let mut cmd = Command::new("cmd");
cmd.arg("/c").arg("set");
cmd
}
#[cfg(not(target_os="android"))]
#[test]
fn test_inherit_env() {
use os;
if running_on_valgrind() { return; }
let prog = env_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
let r = os::env();
2015-01-31 12:20:46 -05:00
for &(ref k, ref v) in &r {
// don't check windows magical empty-named variables
assert!(k.is_empty() ||
output.contains(&format!("{}={}", *k, *v)),
"output doesn't contain `{}={}`\n{}",
k, v, output);
}
}
#[cfg(target_os="android")]
#[test]
fn test_inherit_env() {
use os;
if running_on_valgrind() { return; }
let mut prog = env_cmd().spawn().unwrap();
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
let r = os::env();
2015-01-31 12:20:46 -05:00
for &(ref k, ref v) in &r {
// don't check android RANDOM variables
if *k != "RANDOM".to_string() {
assert!(output.contains(&format!("{}={}",
*k,
*v)) ||
output.contains(&format!("{}=\'{}\'",
*k,
*v)));
}
}
}
#[test]
fn test_override_env() {
use os;
// In some build environments (such as chrooted Nix builds), `env` can
// only be found in the explicitly-provided PATH env variable, not in
// default places such as /bin or /usr/bin. So we need to pass through
// PATH to our sub-process.
let path_val: String;
let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")];
match os::getenv("PATH") {
None => {}
Some(val) => {
path_val = val;
new_env.push(("PATH", &path_val))
}
}
let prog = env_cmd().env_set_all(&new_env).spawn().unwrap();
let result = prog.wait_with_output().unwrap();
let output = String::from_utf8_lossy(&result.output).to_string();
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
}
#[test]
fn test_add_to_env() {
let prog = env_cmd().env("RUN_TEST_NEW_ENV", "123").spawn().unwrap();
let result = prog.wait_with_output().unwrap();
let output = String::from_utf8_lossy(&result.output).to_string();
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
}
#[cfg(unix)]
pub fn sleeper() -> Process {
Command::new("sleep").arg("1000").spawn().unwrap()
}
#[cfg(windows)]
pub fn sleeper() -> Process {
// There's a `timeout` command on windows, but it doesn't like having
// its output piped, so instead just ping ourselves a few times with
2014-06-08 13:22:49 -04:00
// gaps in between so we're sure this process is alive for awhile
Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
}
#[test]
fn test_kill() {
let mut p = sleeper();
Process::kill(p.id(), PleaseExitSignal).unwrap();
assert!(!p.wait().unwrap().success());
}
#[test]
fn test_exists() {
let mut p = sleeper();
assert!(Process::kill(p.id(), 0).is_ok());
p.signal_kill().unwrap();
assert!(!p.wait().unwrap().success());
}
#[test]
fn test_zero() {
let mut p = sleeper();
p.signal_kill().unwrap();
2015-01-25 22:05:03 +01:00
for _ in 0..20 {
if p.signal(0).is_err() {
assert!(!p.wait().unwrap().success());
return
}
timer::sleep(Duration::milliseconds(100));
}
panic!("never saw the child go away");
}
#[test]
fn wait_timeout() {
let mut p = sleeper();
p.set_timeout(Some(10));
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
p.signal_kill().unwrap();
p.set_timeout(None);
assert!(p.wait().is_ok());
}
#[test]
fn wait_timeout2() {
let (tx, rx) = channel();
let tx2 = tx.clone();
2015-02-17 15:10:25 -08:00
let _t = thread::spawn(move|| {
let mut p = sleeper();
p.set_timeout(Some(10));
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
p.signal_kill().unwrap();
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
tx.send(()).unwrap();
});
2015-02-17 15:10:25 -08:00
let _t = thread::spawn(move|| {
let mut p = sleeper();
p.set_timeout(Some(10));
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
p.signal_kill().unwrap();
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
tx2.send(()).unwrap();
});
std: Second pass stabilization for `comm` This commit is a second pass stabilization for the `std::comm` module, performing the following actions: * The entire `std::comm` module was moved under `std::sync::mpsc`. This movement reflects that channels are just yet another synchronization primitive, and they don't necessarily deserve a special place outside of the other concurrency primitives that the standard library offers. * The `send` and `recv` methods have all been removed. * The `send_opt` and `recv_opt` methods have been renamed to `send` and `recv`. This means that all send/receive operations return a `Result` now indicating whether the operation was successful or not. * The error type of `send` is now a `SendError` to implement a custom error message and allow for `unwrap()`. The error type contains an `into_inner` method to extract the value. * The error type of `recv` is now `RecvError` for the same reasons as `send`. * The `TryRecvError` and `TrySendError` types have had public reexports removed of their variants and the variant names have been tweaked with enum namespacing rules. * The `Messages` iterator is renamed to `Iter` This functionality is now all `#[stable]`: * `Sender` * `SyncSender` * `Receiver` * `std::sync::mpsc` * `channel` * `sync_channel` * `Iter` * `Sender::send` * `Sender::clone` * `SyncSender::send` * `SyncSender::try_send` * `SyncSender::clone` * `Receiver::recv` * `Receiver::try_recv` * `Receiver::iter` * `SendError` * `RecvError` * `TrySendError::{mod, Full, Disconnected}` * `TryRecvError::{mod, Empty, Disconnected}` * `SendError::into_inner` * `TrySendError::into_inner` This is a breaking change due to the modification of where this module is located, as well as the changing of the semantics of `send` and `recv`. Most programs just need to rename imports of `std::comm` to `std::sync::mpsc` and add calls to `unwrap` after a send or a receive operation. [breaking-change]
2014-12-23 11:53:35 -08:00
rx.recv().unwrap();
rx.recv().unwrap();
}
#[test]
fn forget() {
let p = sleeper();
let id = p.id();
p.forget();
assert!(Process::kill(id, 0).is_ok());
assert!(Process::kill(id, PleaseExitSignal).is_ok());
}
#[test]
fn dont_close_fd_on_command_spawn() {
use sys::fs;
let path = if cfg!(windows) {
Path::new("NUL")
} else {
Path::new("/dev/null")
};
2014-11-16 10:37:31 +01:00
let fdes = match fs::open(&path, Truncate, Write) {
Ok(f) => f,
Err(_) => panic!("failed to open file descriptor"),
};
let mut cmd = pwd_cmd();
let _ = cmd.stdout(InheritFd(fdes.fd()));
assert!(cmd.status().unwrap().success());
assert!(fdes.write("extra write\n".as_bytes()).is_ok());
}
2014-09-14 01:33:21 -07:00
#[test]
#[cfg(windows)]
fn env_map_keys_ci() {
use ffi::CString;
2014-09-14 01:33:21 -07:00
use super::EnvKey;
let mut cmd = Command::new("");
cmd.env("path", "foo");
cmd.env("Path", "bar");
let env = &cmd.env.unwrap();
let val = env.get(&EnvKey(CString::new("PATH").unwrap()));
assert!(val.unwrap() == &CString::new("bar").unwrap());
2014-09-14 01:33:21 -07:00
}
}