Rollup merge of #114379 - RalfJung:command-removed-env-vars, r=m-ou-se

Command: also print removed env vars

There is no real shell syntax for unsetting an env var so easily, so we have to make one up. But we already do that for showing the 'program' name so I hope that's okay here, too. No strong opinion on what that should look like, I went with `unset(VAR_NAME)` for now.
This commit is contained in:
Matthias Krüger 2023-09-22 12:15:25 +02:00 committed by GitHub
commit 9887dfab2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 2 deletions

View File

@ -789,7 +789,7 @@ impl Command {
/// or [`Command::envs`]. In addition, it will prevent the spawned child process from inheriting
/// any environment variable from its parent process.
///
/// After calling [`Command::env_remove`], the iterator from [`Command::get_envs`] will be
/// After calling [`Command::env_clear`], the iterator from [`Command::get_envs`] will be
/// empty.
///
/// You can use [`Command::env_remove`] to clear a single mapping.

View File

@ -537,7 +537,7 @@ fn env_empty() {
#[test]
#[cfg(not(windows))]
#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
fn main() {
fn debug_print() {
const PIDFD: &'static str =
if cfg!(target_os = "linux") { " create_pidfd: false,\n" } else { "" };
@ -623,6 +623,51 @@ fn main() {
cwd: Some(
"/some/path",
),
{PIDFD}}}"#
)
);
let mut command_with_removed_env = Command::new("boring-name");
command_with_removed_env.env_remove("FOO").env_remove("BAR");
assert_eq!(format!("{command_with_removed_env:?}"), r#"env -u BAR -u FOO "boring-name""#);
assert_eq!(
format!("{command_with_removed_env:#?}"),
format!(
r#"Command {{
program: "boring-name",
args: [
"boring-name",
],
env: CommandEnv {{
clear: false,
vars: {{
"BAR": None,
"FOO": None,
}},
}},
{PIDFD}}}"#
)
);
let mut command_with_cleared_env = Command::new("boring-name");
command_with_cleared_env.env_clear().env("BAR", "val").env_remove("FOO");
assert_eq!(format!("{command_with_cleared_env:?}"), r#"env -i BAR="val" "boring-name""#);
assert_eq!(
format!("{command_with_cleared_env:#?}"),
format!(
r#"Command {{
program: "boring-name",
args: [
"boring-name",
],
env: CommandEnv {{
clear: true,
vars: {{
"BAR": Some(
"val",
),
}},
}},
{PIDFD}}}"#
)
);

View File

@ -586,6 +586,23 @@ impl fmt::Debug for Command {
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())?;

View File

@ -80,6 +80,10 @@ impl CommandEnv {
self.vars.clear();
}
pub fn does_clear(&self) -> bool {
self.clear
}
pub fn have_changed_path(&self) -> bool {
self.saw_path || self.clear
}