Skip to content

Commit 8586a24

Browse files
committed
Store all args in the unsupported Command implementation
This allows printing them in the Debug impl as well as getting them again using the get_args() method. This allows programs that would normally spawn another process to more easily show which program they would have spawned if not for the fact that the target doesn't support spawning child processes without requiring intrusive changes to keep the args. For example rustc compiled to wasi will show the full linker invocation that would have been done.
1 parent 0eefa94 commit 8586a24

File tree

1 file changed

+118
-31
lines changed

1 file changed

+118
-31
lines changed

Diff for: std/src/sys/pal/unsupported/process.rs

+118-31
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::ffi::OsStr;
1+
use crate::ffi::{OsStr, OsString};
22
use crate::fmt;
33
use crate::io;
4-
use crate::marker::PhantomData;
54
use crate::num::NonZero;
65
use crate::path::Path;
76
use crate::sys::fs::File;
@@ -16,7 +15,14 @@ pub use crate::ffi::OsString as EnvKey;
1615
////////////////////////////////////////////////////////////////////////////////
1716

1817
pub struct Command {
18+
program: OsString,
19+
args: Vec<OsString>,
1920
env: CommandEnv,
21+
22+
cwd: Option<OsString>,
23+
stdin: Option<Stdio>,
24+
stdout: Option<Stdio>,
25+
stderr: Option<Stdio>,
2026
}
2127

2228
// passed back to std::process with the pipes connected to the child, if any
@@ -27,47 +33,69 @@ pub struct StdioPipes {
2733
pub stderr: Option<AnonPipe>,
2834
}
2935

30-
// FIXME: This should be a unit struct, so we can always construct it
31-
// The value here should be never used, since we cannot spawn processes.
36+
#[derive(Debug)]
3237
pub enum Stdio {
3338
Inherit,
3439
Null,
3540
MakePipe,
41+
ParentStdout,
42+
ParentStderr,
43+
InheritFile(File),
3644
}
3745

3846
impl Command {
39-
pub fn new(_program: &OsStr) -> Command {
40-
Command { env: Default::default() }
47+
pub fn new(program: &OsStr) -> Command {
48+
Command {
49+
program: program.to_owned(),
50+
args: vec![program.to_owned()],
51+
env: Default::default(),
52+
cwd: None,
53+
stdin: None,
54+
stdout: None,
55+
stderr: None,
56+
}
4157
}
4258

43-
pub fn arg(&mut self, _arg: &OsStr) {}
59+
pub fn arg(&mut self, arg: &OsStr) {
60+
self.args.push(arg.to_owned());
61+
}
4462

4563
pub fn env_mut(&mut self) -> &mut CommandEnv {
4664
&mut self.env
4765
}
4866

49-
pub fn cwd(&mut self, _dir: &OsStr) {}
67+
pub fn cwd(&mut self, dir: &OsStr) {
68+
self.cwd = Some(dir.to_owned());
69+
}
5070

51-
pub fn stdin(&mut self, _stdin: Stdio) {}
71+
pub fn stdin(&mut self, stdin: Stdio) {
72+
self.stdin = Some(stdin);
73+
}
5274

53-
pub fn stdout(&mut self, _stdout: Stdio) {}
75+
pub fn stdout(&mut self, stdout: Stdio) {
76+
self.stdout = Some(stdout);
77+
}
5478

55-
pub fn stderr(&mut self, _stderr: Stdio) {}
79+
pub fn stderr(&mut self, stderr: Stdio) {
80+
self.stderr = Some(stderr);
81+
}
5682

5783
pub fn get_program(&self) -> &OsStr {
58-
panic!("unsupported")
84+
&self.program
5985
}
6086

6187
pub fn get_args(&self) -> CommandArgs<'_> {
62-
CommandArgs { _p: PhantomData }
88+
let mut iter = self.args.iter();
89+
iter.next();
90+
CommandArgs { iter }
6391
}
6492

6593
pub fn get_envs(&self) -> CommandEnvs<'_> {
6694
self.env.iter()
6795
}
6896

6997
pub fn get_current_dir(&self) -> Option<&Path> {
70-
None
98+
self.cwd.as_ref().map(|cs| Path::new(cs))
7199
}
72100

73101
pub fn spawn(
@@ -91,31 +119,83 @@ impl From<AnonPipe> for Stdio {
91119

92120
impl From<io::Stdout> for Stdio {
93121
fn from(_: io::Stdout) -> Stdio {
94-
// FIXME: This is wrong.
95-
// Instead, the Stdio we have here should be a unit struct.
96-
panic!("unsupported")
122+
Stdio::ParentStdout
97123
}
98124
}
99125

100126
impl From<io::Stderr> for Stdio {
101127
fn from(_: io::Stderr) -> Stdio {
102-
// FIXME: This is wrong.
103-
// Instead, the Stdio we have here should be a unit struct.
104-
panic!("unsupported")
128+
Stdio::ParentStderr
105129
}
106130
}
107131

108132
impl From<File> for Stdio {
109-
fn from(_file: File) -> Stdio {
110-
// FIXME: This is wrong.
111-
// Instead, the Stdio we have here should be a unit struct.
112-
panic!("unsupported")
133+
fn from(file: File) -> Stdio {
134+
Stdio::InheritFile(file)
113135
}
114136
}
115137

116138
impl fmt::Debug for Command {
117-
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
118-
Ok(())
139+
// show all attributes
140+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141+
if f.alternate() {
142+
let mut debug_command = f.debug_struct("Command");
143+
debug_command.field("program", &self.program).field("args", &self.args);
144+
if !self.env.is_unchanged() {
145+
debug_command.field("env", &self.env);
146+
}
147+
148+
if self.cwd.is_some() {
149+
debug_command.field("cwd", &self.cwd);
150+
}
151+
152+
if self.stdin.is_some() {
153+
debug_command.field("stdin", &self.stdin);
154+
}
155+
if self.stdout.is_some() {
156+
debug_command.field("stdout", &self.stdout);
157+
}
158+
if self.stderr.is_some() {
159+
debug_command.field("stderr", &self.stderr);
160+
}
161+
162+
debug_command.finish()
163+
} else {
164+
if let Some(ref cwd) = self.cwd {
165+
write!(f, "cd {cwd:?} && ")?;
166+
}
167+
if self.env.does_clear() {
168+
write!(f, "env -i ")?;
169+
// Altered env vars will be printed next, that should exactly work as expected.
170+
} else {
171+
// Removed env vars need the command to be wrapped in `env`.
172+
let mut any_removed = false;
173+
for (key, value_opt) in self.get_envs() {
174+
if value_opt.is_none() {
175+
if !any_removed {
176+
write!(f, "env ")?;
177+
any_removed = true;
178+
}
179+
write!(f, "-u {} ", key.to_string_lossy())?;
180+
}
181+
}
182+
}
183+
// Altered env vars can just be added in front of the program.
184+
for (key, value_opt) in self.get_envs() {
185+
if let Some(value) = value_opt {
186+
write!(f, "{}={value:?} ", key.to_string_lossy())?;
187+
}
188+
}
189+
if self.program != self.args[0] {
190+
write!(f, "[{:?}] ", self.program)?;
191+
}
192+
write!(f, "{:?}", self.args[0])?;
193+
194+
for arg in &self.args[1..] {
195+
write!(f, " {:?}", arg)?;
196+
}
197+
Ok(())
198+
}
119199
}
120200
}
121201

@@ -217,23 +297,30 @@ impl Process {
217297
}
218298

219299
pub struct CommandArgs<'a> {
220-
_p: PhantomData<&'a ()>,
300+
iter: crate::slice::Iter<'a, OsString>,
221301
}
222302

223303
impl<'a> Iterator for CommandArgs<'a> {
224304
type Item = &'a OsStr;
225305
fn next(&mut self) -> Option<&'a OsStr> {
226-
None
306+
self.iter.next().map(|os| &**os)
227307
}
228308
fn size_hint(&self) -> (usize, Option<usize>) {
229-
(0, Some(0))
309+
self.iter.size_hint()
230310
}
231311
}
232312

233-
impl<'a> ExactSizeIterator for CommandArgs<'a> {}
313+
impl<'a> ExactSizeIterator for CommandArgs<'a> {
314+
fn len(&self) -> usize {
315+
self.iter.len()
316+
}
317+
fn is_empty(&self) -> bool {
318+
self.iter.is_empty()
319+
}
320+
}
234321

235322
impl<'a> fmt::Debug for CommandArgs<'a> {
236323
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237-
f.debug_list().finish()
324+
f.debug_list().entries(self.iter.clone()).finish()
238325
}
239326
}

0 commit comments

Comments
 (0)