From 71e0b62bd73924377fc0bf3358a569b2bf25a262 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Sat, 12 Oct 2024 20:17:34 -0700 Subject: [PATCH] Don't leak stderr from cargo locate-project --- src/process.rs | 27 +-------------------------- src/workspace.rs | 31 +++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/process.rs b/src/process.rs index e62d4d26..1a9ab014 100644 --- a/src/process.rs +++ b/src/process.rs @@ -17,7 +17,7 @@ use std::time::{Duration, Instant}; use anyhow::{bail, Context}; use camino::Utf8Path; use serde::Serialize; -use tracing::{debug, debug_span, error, span, trace, warn, Level}; +use tracing::{debug, span, trace, warn, Level}; use crate::console::Console; use crate::interrupt::check_interrupted; @@ -200,31 +200,6 @@ impl ProcessStatus { } } -/// Run a command and return its stdout output as a string. -/// -/// If the command exits non-zero, the error includes any messages it wrote to stderr. -/// -/// The runtime is capped by [METADATA_TIMEOUT]. -pub fn get_command_output(argv: &[&str], cwd: &Utf8Path) -> Result { - // TODO: Perhaps redirect to files so this doesn't jam if there's a lot of output. - // For the commands we use this for today, which only produce small output, it's OK. - let _span = debug_span!("get_command_output", argv = ?argv).entered(); - let output = Command::new(argv[0]) - .args(&argv[1..]) - .stderr(Stdio::inherit()) - .current_dir(cwd) - .output() - .with_context(|| format!("failed to spawn {argv:?}"))?; - let exit = output.status; - if !exit.success() { - error!(?exit, "Child failed"); - bail!("Child failed with status {exit:?}: {argv:?}"); - } - let stdout = String::from_utf8(output.stdout).context("Child output is not UTF-8")?; - debug!("output: {}", stdout.trim()); - Ok(stdout) -} - /// Quote an argv slice in Unix shell style. /// /// This is not completely guaranteed, but is only for debug logs. diff --git a/src/workspace.rs b/src/workspace.rs index 3f899e6c..cf583501 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -3,13 +3,14 @@ use std::fmt; use std::panic::catch_unwind; use std::path::Path; +use std::process::Command; use std::sync::Arc; -use anyhow::{anyhow, ensure, Context}; +use anyhow::{anyhow, bail, ensure, Context}; use camino::{Utf8Path, Utf8PathBuf}; use itertools::Itertools; use serde_json::Value; -use tracing::{debug, debug_span, warn}; +use tracing::{debug, debug_span, error, warn}; use crate::cargo::cargo_bin; use crate::console::Console; @@ -17,7 +18,6 @@ use crate::interrupt::check_interrupted; use crate::mutate::Mutant; use crate::options::Options; use crate::package::Package; -use crate::process::get_command_output; use crate::source::SourceFile; use crate::visit::{walk_tree, Discovered}; use crate::Result; @@ -127,6 +127,7 @@ impl Workspace { let metadata = cargo_metadata::MetadataCommand::new() .no_deps() .manifest_path(&manifest_path) + .verbose(false) .exec() .with_context(|| format!("Failed to run cargo metadata on {:?}", manifest_path))?; debug!(workspace_root = ?metadata.workspace_root, "Found workspace root"); @@ -287,13 +288,27 @@ fn should_mutate_target(target: &cargo_metadata::Target) -> bool { /// Return the path of the workspace or package directory enclosing a given directory. fn locate_project(path: &Utf8Path, workspace: bool) -> Result { ensure!(path.is_dir(), "{path:?} is not a directory"); - let cargo_bin = cargo_bin(); // needed for lifetime - let mut argv: Vec<&str> = vec![&cargo_bin, "locate-project"]; + let mut args: Vec<&str> = vec!["locate-project"]; if workspace { - argv.push("--workspace"); + args.push("--workspace"); } - let stdout = get_command_output(&argv, path) - .with_context(|| format!("run cargo locate-project in {path:?}"))?; + let output = Command::new(cargo_bin()) + .args(&args) + .current_dir(path) + .output() + .with_context(|| format!("failed to spawn {args:?}"))?; + let exit = output.status; + if !exit.success() { + error!( + ?exit, + "cargo locate-project failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + bail!("cargo locate-project failed"); + } + let stdout = + String::from_utf8(output.stdout).context("cargo locate-project output is not UTF-8")?; + debug!("output: {}", stdout.trim()); let val: Value = serde_json::from_str(&stdout).context("parse cargo locate-project output")?; let cargo_toml_path: Utf8PathBuf = val["root"] .as_str()