Skip to content

Commit a3f10a4

Browse files
authored
Rollup merge of rust-lang#123633 - bjorn3:unsupported_command_data, r=jhpratt
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.
2 parents 2ddf984 + b4a395b commit a3f10a4

File tree

1 file changed

+119
-31
lines changed

1 file changed

+119
-31
lines changed

library/std/src/sys/pal/unsupported/process.rs

+119-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,70 @@ 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+
#[allow(dead_code)] // This variant exists only for the Debug impl
44+
InheritFile(File),
3645
}
3746

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

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

4564
pub fn env_mut(&mut self) -> &mut CommandEnv {
4665
&mut self.env
4766
}
4867

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

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

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

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

5784
pub fn get_program(&self) -> &OsStr {
58-
panic!("unsupported")
85+
&self.program
5986
}
6087

6188
pub fn get_args(&self) -> CommandArgs<'_> {
62-
CommandArgs { _p: PhantomData }
89+
let mut iter = self.args.iter();
90+
iter.next();
91+
CommandArgs { iter }
6392
}
6493

6594
pub fn get_envs(&self) -> CommandEnvs<'_> {
6695
self.env.iter()
6796
}
6897

6998
pub fn get_current_dir(&self) -> Option<&Path> {
70-
None
99+
self.cwd.as_ref().map(|cs| Path::new(cs))
71100
}
72101

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

92121
impl From<io::Stdout> for Stdio {
93122
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")
123+
Stdio::ParentStdout
97124
}
98125
}
99126

100127
impl From<io::Stderr> for Stdio {
101128
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")
129+
Stdio::ParentStderr
105130
}
106131
}
107132

108133
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")
134+
fn from(file: File) -> Stdio {
135+
Stdio::InheritFile(file)
113136
}
114137
}
115138

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

@@ -217,23 +298,30 @@ impl Process {
217298
}
218299

219300
pub struct CommandArgs<'a> {
220-
_p: PhantomData<&'a ()>,
301+
iter: crate::slice::Iter<'a, OsString>,
221302
}
222303

223304
impl<'a> Iterator for CommandArgs<'a> {
224305
type Item = &'a OsStr;
225306
fn next(&mut self) -> Option<&'a OsStr> {
226-
None
307+
self.iter.next().map(|os| &**os)
227308
}
228309
fn size_hint(&self) -> (usize, Option<usize>) {
229-
(0, Some(0))
310+
self.iter.size_hint()
230311
}
231312
}
232313

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

235323
impl<'a> fmt::Debug for CommandArgs<'a> {
236324
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237-
f.debug_list().finish()
325+
f.debug_list().entries(self.iter.clone()).finish()
238326
}
239327
}

0 commit comments

Comments
 (0)