Skip to content

Commit

Permalink
Don't leak stderr from cargo locate-project
Browse files Browse the repository at this point in the history
  • Loading branch information
sourcefrog committed Oct 13, 2024
1 parent 66757cd commit 71e0b62
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 34 deletions.
27 changes: 1 addition & 26 deletions src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> {
// 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.
Expand Down
31 changes: 23 additions & 8 deletions src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
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;
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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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<Utf8PathBuf> {
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()
Expand Down

0 comments on commit 71e0b62

Please sign in to comment.