Skip to content

Commit 2a6f3a2

Browse files
committed
More verbose Debug implementation of std::process:Command
Mainly based on commit: zackmdavis@ccc019a from https://github.com/zackmdavis close rust-lang#42200
1 parent 703d95e commit 2a6f3a2

File tree

3 files changed

+34
-13
lines changed

3 files changed

+34
-13
lines changed

library/std/src/process.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,9 +1033,6 @@ impl Command {
10331033

10341034
#[stable(feature = "rust1", since = "1.0.0")]
10351035
impl fmt::Debug for Command {
1036-
/// Format the program and arguments of a Command for display. Any
1037-
/// non-utf8 data is lossily converted using the utf8 replacement
1038-
/// character.
10391036
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10401037
self.inner.fmt(f)
10411038
}

library/std/src/sys/unix/process/process_common.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ pub struct Command {
110110
}
111111

112112
// Create a new type for argv, so that we can make it `Send` and `Sync`
113+
#[derive(Debug)]
113114
struct Argv(Vec<*const c_char>);
114115

115116
// It is safe to make `Argv` `Send` and `Sync`, because it contains
@@ -144,6 +145,7 @@ pub enum ChildStdio {
144145
Null,
145146
}
146147

148+
#[derive(Debug)]
147149
pub enum Stdio {
148150
Inherit,
149151
Null,
@@ -510,16 +512,30 @@ impl ChildStdio {
510512
}
511513

512514
impl fmt::Debug for Command {
515+
// show all attributes but `self.closures` which does not implement `Debug`
513516
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514-
if self.program != self.args[0] {
515-
write!(f, "[{:?}] ", self.program)?;
517+
let mut debug_command = f.debug_struct("Command");
518+
debug_command
519+
.field("program", &self.program)
520+
.field("args", &self.args)
521+
.field("argv", &self.argv)
522+
.field("env", &self.env)
523+
.field("cwd", &self.cwd)
524+
.field("uid", &self.uid)
525+
.field("gid", &self.gid)
526+
.field("saw_nul", &self.saw_nul)
527+
.field("groups", &self.groups)
528+
.field("stdin", &self.stdin)
529+
.field("stdout", &self.stdout)
530+
.field("stderr", &self.stderr)
531+
.field("pgroup", &self.pgroup);
532+
533+
#[cfg(target_os = "linux")]
534+
{
535+
debug_command.field("create_pidfd", &self.create_pidfd);
516536
}
517-
write!(f, "{:?}", self.args[0])?;
518537

519-
for arg in &self.args[1..] {
520-
write!(f, " {:?}", arg)?;
521-
}
522-
Ok(())
538+
debug_command.finish()
523539
}
524540
}
525541

src/test/ui/command/command-argv0-debug.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,27 @@
33
// ignore-windows - this is a unix-specific test
44
// ignore-emscripten no processes
55
// ignore-sgx no processes
6+
// ignore-tidy-linelength
67
use std::os::unix::process::CommandExt;
78
use std::process::Command;
89

10+
// `argv` attribute changes each time the test is made so needs to be retrieved dynamically
11+
// There is no public API to access it so we need to parse the debug output
12+
// Example of returned String: "[0x600010bb8000, 0x600010bb80a0]"
13+
fn get_argv(cmd: &Command) -> String {
14+
format!("{cmd:?}").split_once("Argv(").and_then(|(_, after)| after.split_once(")")).unwrap().0.to_string()
15+
}
16+
917
fn main() {
1018
let mut command = Command::new("some-boring-name");
1119

12-
assert_eq!(format!("{:?}", command), r#""some-boring-name""#);
20+
assert_eq!(format!("{command:?}"), format!(r#"Command {{ program: "some-boring-name", args: ["some-boring-name"], argv: Argv({}), env: CommandEnv {{ clear: false, saw_path: false, vars: {{}} }}, cwd: None, uid: None, gid: None, saw_nul: false, groups: None, stdin: None, stdout: None, stderr: None, pgroup: None }}"#, get_argv(&command)));
1321

1422
command.args(&["1", "2", "3"]);
1523

16-
assert_eq!(format!("{:?}", command), r#""some-boring-name" "1" "2" "3""#);
24+
assert_eq!(format!("{command:?}"), format!(r#"Command {{ program: "some-boring-name", args: ["some-boring-name", "1", "2", "3"], argv: Argv({}), env: CommandEnv {{ clear: false, saw_path: false, vars: {{}} }}, cwd: None, uid: None, gid: None, saw_nul: false, groups: None, stdin: None, stdout: None, stderr: None, pgroup: None }}"#, get_argv(&command)));
1725

1826
command.arg0("exciting-name");
1927

20-
assert_eq!(format!("{:?}", command), r#"["some-boring-name"] "exciting-name" "1" "2" "3""#);
28+
assert_eq!(format!("{command:?}"), format!(r#"Command {{ program: "some-boring-name", args: ["exciting-name", "1", "2", "3"], argv: Argv({}), env: CommandEnv {{ clear: false, saw_path: false, vars: {{}} }}, cwd: None, uid: None, gid: None, saw_nul: false, groups: None, stdin: None, stdout: None, stderr: None, pgroup: None }}"#, get_argv(&command)));
2129
}

0 commit comments

Comments
 (0)