use std::{
env::var,
fs::copy,
os::unix::fs::chown,
path::{Path, PathBuf},
};
use log::debug;
use which::which;
use crate::{Error, IoError};
pub const COVERAGE_ENV_LIST: &[&str] = &[
"LLVM_PROFILE_FILE",
"CARGO_LLVM_COV",
"CARGO_LLVM_COV_SHOW_ENV",
"CARGO_LLVM_COV_TARGET_DIR",
"RUSTFLAGS",
"RUSTDOCFLAGS",
];
pub fn collect_coverage_data(path: impl AsRef<Path>) -> Result<(), crate::Error> {
let path = path.as_ref();
let cov_target_dir = {
let Ok(cov_target_dir) = var("CARGO_LLVM_COV_TARGET_DIR") else {
return Err(crate::Error::CargoLlvmCovTargetDirNotSet);
};
debug!("Found CARGO_LLVM_COV_TARGET_DIR={cov_target_dir}");
PathBuf::from(cov_target_dir)
};
for dir_entry in path
.read_dir()
.map_io_path_err(path, "reading directory entries")?
{
let dir_entry = dir_entry.map_io_path_err(path, "accessing a child in the directory")?;
let from = dir_entry.path();
let Some(file_name) = &from.file_name() else {
continue;
};
if from
.extension()
.is_some_and(|extension| extension == "profraw")
{
let target_file = cov_target_dir.join(file_name);
debug!("Copying {from:?} to {target_file:?}");
copy(&from, &target_file)
.map_io_path_err(path, format!("copying file to {target_file:?}"))?;
chown(&target_file, Some(0), Some(0))
.map_io_path_err(target_file, "changing ownership to root")?;
}
}
Ok(())
}
pub fn get_command(command: &str) -> Result<PathBuf, Error> {
which(command).map_err(|source| Error::ExecutableNotFound {
command: command.to_string(),
source,
})
}
#[cfg(test)]
#[cfg(target_os = "linux")]
mod tests {
use rstest::rstest;
use testresult::TestResult;
use super::*;
#[rstest]
#[case("whoami")]
#[case("/usr/bin/whoami")]
fn get_command_succeeds(#[case] cmd: &str) -> TestResult {
get_command(cmd)?;
Ok(())
}
#[test]
fn get_command_fails() -> TestResult {
let bogus_cmd = "d202d7951df2c4b711ca44b4bcc9d7b363fa4252127e058c1a910ec05b6cd038d71cc21221c031c0359f993e746b07f5965cf8c5c3746a58337ad9ab65278e77";
if let Ok(path) = get_command(bogus_cmd) {
panic!("The command {bogus_cmd} shouldn't exist, but {path:?} is found!");
}
Ok(())
}
}