Skip to content

Store all args in the unsupported Command implementation #123633

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

Merged
merged 2 commits into from
Apr 10, 2024
Merged
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
150 changes: 119 additions & 31 deletions library/std/src/sys/pal/unsupported/process.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::ffi::OsStr;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
use crate::num::NonZero;
use crate::path::Path;
use crate::sys::fs::File;
Expand All @@ -16,7 +15,14 @@ pub use crate::ffi::OsString as EnvKey;
////////////////////////////////////////////////////////////////////////////////

pub struct Command {
program: OsString,
args: Vec<OsString>,
env: CommandEnv,

cwd: Option<OsString>,
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
}

// passed back to std::process with the pipes connected to the child, if any
Expand All @@ -27,47 +33,70 @@ pub struct StdioPipes {
pub stderr: Option<AnonPipe>,
}

// FIXME: This should be a unit struct, so we can always construct it
// The value here should be never used, since we cannot spawn processes.
#[derive(Debug)]
pub enum Stdio {
Inherit,
Null,
MakePipe,
ParentStdout,
ParentStderr,
#[allow(dead_code)] // This variant exists only for the Debug impl
InheritFile(File),
}

impl Command {
pub fn new(_program: &OsStr) -> Command {
Command { env: Default::default() }
pub fn new(program: &OsStr) -> Command {
Command {
program: program.to_owned(),
args: vec![program.to_owned()],
env: Default::default(),
cwd: None,
stdin: None,
stdout: None,
stderr: None,
}
}

pub fn arg(&mut self, _arg: &OsStr) {}
pub fn arg(&mut self, arg: &OsStr) {
self.args.push(arg.to_owned());
}

pub fn env_mut(&mut self) -> &mut CommandEnv {
&mut self.env
}

pub fn cwd(&mut self, _dir: &OsStr) {}
pub fn cwd(&mut self, dir: &OsStr) {
self.cwd = Some(dir.to_owned());
}

pub fn stdin(&mut self, _stdin: Stdio) {}
pub fn stdin(&mut self, stdin: Stdio) {
self.stdin = Some(stdin);
}

pub fn stdout(&mut self, _stdout: Stdio) {}
pub fn stdout(&mut self, stdout: Stdio) {
self.stdout = Some(stdout);
}

pub fn stderr(&mut self, _stderr: Stdio) {}
pub fn stderr(&mut self, stderr: Stdio) {
self.stderr = Some(stderr);
}

pub fn get_program(&self) -> &OsStr {
panic!("unsupported")
&self.program
}

pub fn get_args(&self) -> CommandArgs<'_> {
CommandArgs { _p: PhantomData }
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> {
None
self.cwd.as_ref().map(|cs| Path::new(cs))
}

pub fn spawn(
Expand All @@ -91,31 +120,83 @@ impl From<AnonPipe> for Stdio {

impl From<io::Stdout> for Stdio {
fn from(_: io::Stdout) -> Stdio {
// FIXME: This is wrong.
// Instead, the Stdio we have here should be a unit struct.
panic!("unsupported")
Stdio::ParentStdout
}
}

impl From<io::Stderr> for Stdio {
fn from(_: io::Stderr) -> Stdio {
// FIXME: This is wrong.
// Instead, the Stdio we have here should be a unit struct.
panic!("unsupported")
Stdio::ParentStderr
}
}

impl From<File> for Stdio {
fn from(_file: File) -> Stdio {
// FIXME: This is wrong.
// Instead, the Stdio we have here should be a unit struct.
panic!("unsupported")
fn from(file: File) -> Stdio {
Stdio::InheritFile(file)
}
}

impl fmt::Debug for Command {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
// show all attributes
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
let mut debug_command = f.debug_struct("Command");
debug_command.field("program", &self.program).field("args", &self.args);
if !self.env.is_unchanged() {
debug_command.field("env", &self.env);
}

if self.cwd.is_some() {
debug_command.field("cwd", &self.cwd);
}

if self.stdin.is_some() {
debug_command.field("stdin", &self.stdin);
}
if self.stdout.is_some() {
debug_command.field("stdout", &self.stdout);
}
if self.stderr.is_some() {
debug_command.field("stderr", &self.stderr);
}

debug_command.finish()
} else {
if let Some(ref cwd) = self.cwd {
write!(f, "cd {cwd:?} && ")?;
}
if self.env.does_clear() {
write!(f, "env -i ")?;
// Altered env vars will be printed next, that should exactly work as expected.
} else {
// Removed env vars need the command to be wrapped in `env`.
let mut any_removed = false;
for (key, value_opt) in self.get_envs() {
if value_opt.is_none() {
if !any_removed {
write!(f, "env ")?;
any_removed = true;
}
write!(f, "-u {} ", key.to_string_lossy())?;
}
}
}
// Altered env vars can just be added in front of the program.
for (key, value_opt) in self.get_envs() {
if let Some(value) = value_opt {
write!(f, "{}={value:?} ", key.to_string_lossy())?;
}
}
if self.program != self.args[0] {
write!(f, "[{:?}] ", self.program)?;
}
write!(f, "{:?}", self.args[0])?;

for arg in &self.args[1..] {
write!(f, " {:?}", arg)?;
}
Ok(())
}
}
}

Expand Down Expand Up @@ -217,23 +298,30 @@ impl Process {
}

pub struct CommandArgs<'a> {
_p: PhantomData<&'a ()>,
iter: crate::slice::Iter<'a, OsString>,
}

impl<'a> Iterator for CommandArgs<'a> {
type Item = &'a OsStr;
fn next(&mut self) -> Option<&'a OsStr> {
None
self.iter.next().map(|os| &**os)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(0))
self.iter.size_hint()
}
}

impl<'a> ExactSizeIterator for CommandArgs<'a> {}
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().finish()
f.debug_list().entries(self.iter.clone()).finish()
}
}
Loading