Add accessors to Command.
This commit is contained in:
parent
623fb90b5a
commit
c297e20e03
|
@ -110,6 +110,8 @@ use crate::path::Path;
|
||||||
use crate::str;
|
use crate::str;
|
||||||
use crate::sys::pipe::{read2, AnonPipe};
|
use crate::sys::pipe::{read2, AnonPipe};
|
||||||
use crate::sys::process as imp;
|
use crate::sys::process as imp;
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
pub use crate::sys_common::process::CommandEnvs;
|
||||||
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||||
|
|
||||||
/// Representation of a running or exited child process.
|
/// Representation of a running or exited child process.
|
||||||
|
@ -894,6 +896,98 @@ impl Command {
|
||||||
.map(Child::from_inner)
|
.map(Child::from_inner)
|
||||||
.and_then(|mut p| p.wait())
|
.and_then(|mut p| p.wait())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the path to the program that was given to [`Command::new`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(command_access)]
|
||||||
|
/// use std::process::Command;
|
||||||
|
///
|
||||||
|
/// let cmd = Command::new("echo");
|
||||||
|
/// assert_eq!(cmd.get_program(), "echo");
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
pub fn get_program(&self) -> &OsStr {
|
||||||
|
self.inner.get_program()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator of the arguments that will be passed to the program.
|
||||||
|
///
|
||||||
|
/// This does not include the path to the program as the first argument;
|
||||||
|
/// it only includes the arguments specified with [`Command::arg`] and
|
||||||
|
/// [`Command::args`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(command_access)]
|
||||||
|
/// use std::ffi::OsStr;
|
||||||
|
/// use std::process::Command;
|
||||||
|
///
|
||||||
|
/// let mut cmd = Command::new("echo");
|
||||||
|
/// cmd.arg("first").arg("second");
|
||||||
|
/// let args: Vec<&OsStr> = cmd.get_args().collect();
|
||||||
|
/// assert_eq!(args, &["first", "second"]);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
pub fn get_args(&self) -> CommandArgs<'_> {
|
||||||
|
CommandArgs { inner: self.inner.get_args() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator of the environment variables that will be set when
|
||||||
|
/// the process is spawned.
|
||||||
|
///
|
||||||
|
/// Each element is a tuple `(&OsStr, Option<&OsStr>)`, where the first
|
||||||
|
/// value is the key, and the second is the value, which is [`None`] if
|
||||||
|
/// the environment variable is to be explicitly removed.
|
||||||
|
///
|
||||||
|
/// This only includes environment variables explicitly set with
|
||||||
|
/// [`Command::env`], [`Command::envs`], and [`Command::env_remove`]. It
|
||||||
|
/// does not include environment variables that will be inherited by the
|
||||||
|
/// child process.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(command_access)]
|
||||||
|
/// use std::ffi::OsStr;
|
||||||
|
/// use std::process::Command;
|
||||||
|
///
|
||||||
|
/// let mut cmd = Command::new("ls");
|
||||||
|
/// cmd.env("TERM", "dumb").env_remove("TZ");
|
||||||
|
/// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect();
|
||||||
|
/// assert_eq!(envs, &[
|
||||||
|
/// (OsStr::new("TERM"), Some(OsStr::new("dumb"))),
|
||||||
|
/// (OsStr::new("TZ"), None)
|
||||||
|
/// ]);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
||||||
|
self.inner.get_envs()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the working directory for the child process.
|
||||||
|
///
|
||||||
|
/// This returns [`None`] if the working directory will not be changed.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #![feature(command_access)]
|
||||||
|
/// use std::path::Path;
|
||||||
|
/// use std::process::Command;
|
||||||
|
///
|
||||||
|
/// let mut cmd = Command::new("ls");
|
||||||
|
/// assert_eq!(cmd.get_current_dir(), None);
|
||||||
|
/// cmd.current_dir("/bin");
|
||||||
|
/// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin")));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
pub fn get_current_dir(&self) -> Option<&Path> {
|
||||||
|
self.inner.get_current_dir()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -918,6 +1012,37 @@ impl AsInnerMut<imp::Command> for Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator over the command arguments.
|
||||||
|
///
|
||||||
|
/// This struct is created by [`Command::get_args`]. See its documentation for
|
||||||
|
/// more.
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CommandArgs<'a> {
|
||||||
|
inner: imp::CommandArgs<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
impl<'a> Iterator for CommandArgs<'a> {
|
||||||
|
type Item = &'a OsStr;
|
||||||
|
fn next(&mut self) -> Option<&'a OsStr> {
|
||||||
|
self.inner.next()
|
||||||
|
}
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.inner.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
impl<'a> ExactSizeIterator for CommandArgs<'a> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.inner.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The output of a finished process.
|
/// The output of a finished process.
|
||||||
///
|
///
|
||||||
/// This is returned in a Result by either the [`output`] method of a
|
/// This is returned in a Result by either the [`output`] method of a
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
pub use self::process_common::{Command, ExitCode, Stdio, StdioPipes};
|
pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
|
||||||
pub use self::process_inner::{ExitStatus, Process};
|
pub use self::process_inner::{ExitStatus, Process};
|
||||||
pub use crate::ffi::OsString as EnvKey;
|
pub use crate::ffi::OsString as EnvKey;
|
||||||
|
pub use crate::sys_common::process::CommandEnvs;
|
||||||
|
|
||||||
mod process_common;
|
mod process_common;
|
||||||
#[cfg(not(target_os = "fuchsia"))]
|
#[cfg(not(target_os = "fuchsia"))]
|
||||||
|
|
|
@ -7,11 +7,12 @@ use crate::collections::BTreeMap;
|
||||||
use crate::ffi::{CStr, CString, OsStr, OsString};
|
use crate::ffi::{CStr, CString, OsStr, OsString};
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
|
use crate::path::Path;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
use crate::sys::fd::FileDesc;
|
use crate::sys::fd::FileDesc;
|
||||||
use crate::sys::fs::File;
|
use crate::sys::fs::File;
|
||||||
use crate::sys::pipe::{self, AnonPipe};
|
use crate::sys::pipe::{self, AnonPipe};
|
||||||
use crate::sys_common::process::CommandEnv;
|
use crate::sys_common::process::{CommandEnv, CommandEnvs};
|
||||||
|
|
||||||
#[cfg(not(target_os = "fuchsia"))]
|
#[cfg(not(target_os = "fuchsia"))]
|
||||||
use crate::sys::fs::OpenOptions;
|
use crate::sys::fs::OpenOptions;
|
||||||
|
@ -184,11 +185,30 @@ impl Command {
|
||||||
pub fn saw_nul(&self) -> bool {
|
pub fn saw_nul(&self) -> bool {
|
||||||
self.saw_nul
|
self.saw_nul
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_program(&self) -> &OsStr {
|
||||||
|
OsStr::from_bytes(self.program.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_args(&self) -> CommandArgs<'_> {
|
||||||
|
let mut iter = self.args.iter();
|
||||||
|
iter.next();
|
||||||
|
CommandArgs { iter }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
||||||
|
self.env.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_dir(&self) -> Option<&Path> {
|
||||||
|
self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes())))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_argv(&self) -> &Vec<*const c_char> {
|
pub fn get_argv(&self) -> &Vec<*const c_char> {
|
||||||
&self.argv.0
|
&self.argv.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_program(&self) -> &CStr {
|
pub fn get_program_cstr(&self) -> &CStr {
|
||||||
&*self.program
|
&*self.program
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,3 +422,32 @@ impl ExitCode {
|
||||||
self.0 as i32
|
self.0 as i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CommandArgs<'a> {
|
||||||
|
iter: crate::slice::Iter<'a, CString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for CommandArgs<'a> {
|
||||||
|
type Item = &'a OsStr;
|
||||||
|
fn next(&mut self) -> Option<&'a OsStr> {
|
||||||
|
self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes()))
|
||||||
|
}
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.iter.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExactSizeIterator for CommandArgs<'a> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.iter.len()
|
||||||
|
}
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.iter.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for CommandArgs<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_list().entries(self.iter.clone()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ impl Command {
|
||||||
| FDIO_SPAWN_CLONE_NAMESPACE
|
| FDIO_SPAWN_CLONE_NAMESPACE
|
||||||
| FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
|
| FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
|
||||||
| FDIO_SPAWN_CLONE_UTC_CLOCK,
|
| FDIO_SPAWN_CLONE_UTC_CLOCK,
|
||||||
self.get_program().as_ptr(),
|
self.get_program_cstr().as_ptr(),
|
||||||
self.get_argv().as_ptr(),
|
self.get_argv().as_ptr(),
|
||||||
envp,
|
envp,
|
||||||
actions.len() as size_t,
|
actions.len() as size_t,
|
||||||
|
|
|
@ -245,7 +245,7 @@ impl Command {
|
||||||
*sys::os::environ() = envp.as_ptr();
|
*sys::os::environ() = envp.as_ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
libc::execvp(self.get_program().as_ptr(), self.get_argv().as_ptr());
|
libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr());
|
||||||
Err(io::Error::last_os_error())
|
Err(io::Error::last_os_error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ impl Command {
|
||||||
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
|
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
|
||||||
let ret = libc::posix_spawnp(
|
let ret = libc::posix_spawnp(
|
||||||
&mut p.pid,
|
&mut p.pid,
|
||||||
self.get_program().as_ptr(),
|
self.get_program_cstr().as_ptr(),
|
||||||
file_actions.0.as_ptr(),
|
file_actions.0.as_ptr(),
|
||||||
attrs.0.as_ptr(),
|
attrs.0.as_ptr(),
|
||||||
self.get_argv().as_ptr() as *const _,
|
self.get_argv().as_ptr() as *const _,
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::ffi::OsStr;
|
use crate::ffi::OsStr;
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
|
use crate::marker::PhantomData;
|
||||||
|
use crate::path::Path;
|
||||||
use crate::sys::fs::File;
|
use crate::sys::fs::File;
|
||||||
use crate::sys::pipe::AnonPipe;
|
use crate::sys::pipe::AnonPipe;
|
||||||
use crate::sys::{unsupported, Void};
|
use crate::sys::{unsupported, Void};
|
||||||
use crate::sys_common::process::CommandEnv;
|
use crate::sys_common::process::{CommandEnv, CommandEnvs};
|
||||||
|
|
||||||
pub use crate::ffi::OsString as EnvKey;
|
pub use crate::ffi::OsString as EnvKey;
|
||||||
|
|
||||||
|
@ -49,6 +51,22 @@ impl Command {
|
||||||
|
|
||||||
pub fn stderr(&mut self, _stderr: Stdio) {}
|
pub fn stderr(&mut self, _stderr: Stdio) {}
|
||||||
|
|
||||||
|
pub fn get_program(&self) -> &OsStr {
|
||||||
|
panic!("unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_args(&self) -> CommandArgs<'_> {
|
||||||
|
CommandArgs { _p: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
||||||
|
self.env.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_dir(&self) -> Option<&Path> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn(
|
pub fn spawn(
|
||||||
&mut self,
|
&mut self,
|
||||||
_default: Stdio,
|
_default: Stdio,
|
||||||
|
@ -147,3 +165,22 @@ impl Process {
|
||||||
match self.0 {}
|
match self.0 {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CommandArgs<'a> {
|
||||||
|
_p: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for CommandArgs<'a> {
|
||||||
|
type Item = &'a OsStr;
|
||||||
|
fn next(&mut self) -> Option<&'a OsStr> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExactSizeIterator for CommandArgs<'a> {}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for CommandArgs<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_list().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::sys::handle::Handle;
|
||||||
use crate::sys::mutex::Mutex;
|
use crate::sys::mutex::Mutex;
|
||||||
use crate::sys::pipe::{self, AnonPipe};
|
use crate::sys::pipe::{self, AnonPipe};
|
||||||
use crate::sys::stdio;
|
use crate::sys::stdio;
|
||||||
use crate::sys_common::process::CommandEnv;
|
use crate::sys_common::process::{CommandEnv, CommandEnvs};
|
||||||
use crate::sys_common::AsInner;
|
use crate::sys_common::AsInner;
|
||||||
|
|
||||||
use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
|
use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
|
||||||
|
@ -134,6 +134,23 @@ impl Command {
|
||||||
self.flags = flags;
|
self.flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_program(&self) -> &OsStr {
|
||||||
|
&self.program
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_args(&self) -> CommandArgs<'_> {
|
||||||
|
let iter = self.args.iter();
|
||||||
|
CommandArgs { iter }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
||||||
|
self.env.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_dir(&self) -> Option<&Path> {
|
||||||
|
self.cwd.as_ref().map(|cwd| Path::new(cwd))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn(
|
pub fn spawn(
|
||||||
&mut self,
|
&mut self,
|
||||||
default: Stdio,
|
default: Stdio,
|
||||||
|
@ -529,3 +546,32 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
|
||||||
None => Ok((ptr::null(), Vec::new())),
|
None => Ok((ptr::null(), Vec::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CommandArgs<'a> {
|
||||||
|
iter: crate::slice::Iter<'a, OsString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for CommandArgs<'a> {
|
||||||
|
type Item = &'a OsStr;
|
||||||
|
fn next(&mut self) -> Option<&'a OsStr> {
|
||||||
|
self.iter.next().map(|s| s.as_ref())
|
||||||
|
}
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.iter.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExactSizeIterator for CommandArgs<'a> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.iter.len()
|
||||||
|
}
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.iter.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for CommandArgs<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_list().entries(self.iter.clone()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -92,4 +92,41 @@ impl CommandEnv {
|
||||||
self.saw_path = true;
|
self.saw_path = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> CommandEnvs<'_> {
|
||||||
|
let iter = self.vars.iter();
|
||||||
|
CommandEnvs { iter }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over the command environment variables.
|
||||||
|
///
|
||||||
|
/// This struct is created by
|
||||||
|
/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
|
||||||
|
/// documentation for more.
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CommandEnvs<'a> {
|
||||||
|
iter: crate::collections::btree_map::Iter<'a, EnvKey, Option<OsString>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
impl<'a> Iterator for CommandEnvs<'a> {
|
||||||
|
type Item = (&'a OsStr, Option<&'a OsStr>);
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref()))
|
||||||
|
}
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.iter.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "command_access", issue = "44434")]
|
||||||
|
impl<'a> ExactSizeIterator for CommandEnvs<'a> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.iter.len()
|
||||||
|
}
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.iter.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue