use std::path::Path;
use std::process::{Command, Stdio};
use anyhow::{Context, Result, bail};
use crate::coverage_io::llvm_cov_failure::LlvmCovFailure;
use crate::invocation::config::Config;
use crate::invocation::package_context::PackageContext;
pub struct LlvmCovBuilder {
command: Command,
}
impl LlvmCovBuilder {
pub fn new(output_path: &Path) -> Self {
let mut command = Command::new("cargo");
command.arg("llvm-cov");
command.arg("--json");
command.arg("--output-path");
command.arg(output_path);
Self { command }
}
#[must_use]
pub fn arguments(&self) -> Vec<String> {
self.command
.get_args()
.map(|argument| argument.to_string_lossy().into_owned())
.collect()
}
pub fn apply_config(mut self, config: &Config) -> Self {
if let Some(manifest_path) = &config.manifest_path {
self.command.arg("--manifest-path");
self.command.arg(manifest_path);
}
if let Some(features) = &config.features {
self.command.arg("--features");
self.command.arg(features);
}
if config.all_features {
self.command.arg("--all-features");
}
if config.no_default_features {
self.command.arg("--no-default-features");
}
self
}
pub(crate) fn add_packages(mut self, packages: &[PackageContext]) -> Self {
for package in packages {
self.command.arg("--package");
self.command.arg(&package.name);
}
self
}
pub(crate) fn execute(mut self) -> Result<()> {
self.command.stderr(Stdio::piped());
let output = self
.command
.spawn()
.and_then(|child| child.wait_with_output())
.context("failed to invoke cargo; ensure cargo is on the PATH")?;
if !output.status.success() {
let failure = LlvmCovFailure::new(
output.status.code(),
String::from_utf8_lossy(&output.stderr).into_owned(),
);
bail!("{}", failure.describe());
}
Ok(())
}
}