Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add accessors to Command. #77029

Merged
merged 1 commit into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions library/std/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ use crate::path::Path;
use crate::str;
use crate::sys::pipe::{read2, AnonPipe};
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};

/// Representation of a running or exited child process.
Expand Down Expand Up @@ -894,6 +896,98 @@ impl Command {
.map(Child::from_inner)
.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")]
Expand All @@ -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.
///
/// This is returned in a Result by either the [`output`] method of a
Expand Down
3 changes: 2 additions & 1 deletion library/std/src/sys/unix/process/mod.rs
Original file line number Diff line number Diff line change
@@ -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 crate::ffi::OsString as EnvKey;
pub use crate::sys_common::process::CommandEnvs;

mod process_common;
#[cfg(not(target_os = "fuchsia"))]
Expand Down
53 changes: 51 additions & 2 deletions library/std/src/sys/unix/process/process_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ use crate::collections::BTreeMap;
use crate::ffi::{CStr, CString, OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::path::Path;
use crate::ptr;
use crate::sys::fd::FileDesc;
use crate::sys::fs::File;
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::CommandEnv;
use crate::sys_common::process::{CommandEnv, CommandEnvs};

#[cfg(not(target_os = "fuchsia"))]
use crate::sys::fs::OpenOptions;
Expand Down Expand Up @@ -184,11 +185,30 @@ impl Command {
pub fn saw_nul(&self) -> bool {
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> {
&self.argv.0
}

pub fn get_program(&self) -> &CStr {
pub fn get_program_cstr(&self) -> &CStr {
&*self.program
}

Expand Down Expand Up @@ -402,3 +422,32 @@ impl ExitCode {
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()
}
}
2 changes: 1 addition & 1 deletion library/std/src/sys/unix/process/process_fuchsia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl Command {
| FDIO_SPAWN_CLONE_NAMESPACE
| FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
| FDIO_SPAWN_CLONE_UTC_CLOCK,
self.get_program().as_ptr(),
self.get_program_cstr().as_ptr(),
self.get_argv().as_ptr(),
envp,
actions.len() as size_t,
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/sys/unix/process/process_unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ impl Command {
*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())
}

Expand Down Expand Up @@ -383,7 +383,7 @@ impl Command {
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
let ret = libc::posix_spawnp(
&mut p.pid,
self.get_program().as_ptr(),
self.get_program_cstr().as_ptr(),
file_actions.0.as_ptr(),
attrs.0.as_ptr(),
self.get_argv().as_ptr() as *const _,
Expand Down
39 changes: 38 additions & 1 deletion library/std/src/sys/unsupported/process.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::ffi::OsStr;
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
use crate::path::Path;
use crate::sys::fs::File;
use crate::sys::pipe::AnonPipe;
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;

Expand Down Expand Up @@ -49,6 +51,22 @@ impl Command {

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(
&mut self,
_default: Stdio,
Expand Down Expand Up @@ -147,3 +165,22 @@ impl Process {
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()
}
}
48 changes: 47 additions & 1 deletion library/std/src/sys/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::sys::handle::Handle;
use crate::sys::mutex::Mutex;
use crate::sys::pipe::{self, AnonPipe};
use crate::sys::stdio;
use crate::sys_common::process::CommandEnv;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::sys_common::AsInner;

use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
Expand Down Expand Up @@ -134,6 +134,23 @@ impl Command {
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(
&mut self,
default: Stdio,
Expand Down Expand Up @@ -529,3 +546,32 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
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()
}
}
Loading