Skip to content

Commit

Permalink
More verbose Debug implementation of std::process:Command
Browse files Browse the repository at this point in the history
  • Loading branch information
kraktus committed Dec 3, 2022
1 parent 703d95e commit 2a6f3a2
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
3 changes: 0 additions & 3 deletions library/std/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,9 +1033,6 @@ impl Command {

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Command {
/// Format the program and arguments of a Command for display. Any
/// non-utf8 data is lossily converted using the utf8 replacement
/// character.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
Expand Down
30 changes: 23 additions & 7 deletions library/std/src/sys/unix/process/process_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ pub struct Command {
}

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

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

#[derive(Debug)]
pub enum Stdio {
Inherit,
Null,
Expand Down Expand Up @@ -510,16 +512,30 @@ impl ChildStdio {
}

impl fmt::Debug for Command {
// show all attributes but `self.closures` which does not implement `Debug`
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.program != self.args[0] {
write!(f, "[{:?}] ", self.program)?;
let mut debug_command = f.debug_struct("Command");
debug_command
.field("program", &self.program)
.field("args", &self.args)
.field("argv", &self.argv)
.field("env", &self.env)
.field("cwd", &self.cwd)
.field("uid", &self.uid)
.field("gid", &self.gid)
.field("saw_nul", &self.saw_nul)
.field("groups", &self.groups)
.field("stdin", &self.stdin)
.field("stdout", &self.stdout)
.field("stderr", &self.stderr)
.field("pgroup", &self.pgroup);

#[cfg(target_os = "linux")]
{
debug_command.field("create_pidfd", &self.create_pidfd);
}
write!(f, "{:?}", self.args[0])?;

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

Expand Down
14 changes: 11 additions & 3 deletions src/test/ui/command/command-argv0-debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@
// ignore-windows - this is a unix-specific test
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-tidy-linelength
use std::os::unix::process::CommandExt;
use std::process::Command;

// `argv` attribute changes each time the test is made so needs to be retrieved dynamically
// There is no public API to access it so we need to parse the debug output
// Example of returned String: "[0x600010bb8000, 0x600010bb80a0]"
fn get_argv(cmd: &Command) -> String {
format!("{cmd:?}").split_once("Argv(").and_then(|(_, after)| after.split_once(")")).unwrap().0.to_string()
}

fn main() {
let mut command = Command::new("some-boring-name");

assert_eq!(format!("{:?}", command), r#""some-boring-name""#);
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)));

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

assert_eq!(format!("{:?}", command), r#""some-boring-name" "1" "2" "3""#);
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)));

command.arg0("exciting-name");

assert_eq!(format!("{:?}", command), r#"["some-boring-name"] "exciting-name" "1" "2" "3""#);
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)));
}

0 comments on commit 2a6f3a2

Please sign in to comment.