Auto merge of #77029 - ehuss:command-access, r=dtolnay
Add accessors to Command.
This adds some accessor methods to `Command` to provide a way to access the values set when building the `Command`. An example where this can be useful is to display the command to be executed. This is roughly based on the [`ProcessBuilder`](13b73cdaf7/src/cargo/util/process_builder.rs (L105-L134)
) in Cargo.
Possible concerns about the API:
- Values with NULs on Unix will be returned as `"<string-with-nul>"`. I don't think it is practical to avoid this, since otherwise a whole separate copy of all the values would need to be kept in `Command`.
- Does not handle `arg0` on Unix. This can be awkward to support in `get_args` and is rarely used. I figure if someone really wants it, it can be added to `CommandExt` as a separate method.
- Does not offer a way to detect `env_clear`. I'm uncertain if it would be useful for anyone.
- Does not offer a way to get an environment variable by name (`get_env`). I figure this can be added later if anyone really wants it. I think the motivation for this is weak, though. Also, the API could be a little awkward (return a `Option<Option<&OsStr>>`?).
- `get_envs` could skip "cleared" entries and just return `&OsStr` values instead of `Option<&OsStr>`. I'm on the fence here. My use case is to display a shell command, and I only intend it to be roughly equivalent to the actual execution, and I probably won't display `None` entries. I erred on the side of providing extra information, but I suspect many situations will just filter out the `None`s.
- Could implement more iterator stuff (like `DoubleEndedIterator`).
I have not implemented new std items before, so I'm uncertain if the existing issue should be reused, or if a new tracking issue is needed.
cc #44434
This commit is contained in:
commit
154f1f544d
8 changed files with 303 additions and 8 deletions
|
@ -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"))]
|
||||
|
|
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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 _,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue