use anyhow::Context;
use std::path::{Path, PathBuf};
pub trait CargoInfoProvider: Fn(&Path) -> anyhow::Result<CargoInfo> + Send + Sync {}
impl<T> CargoInfoProvider for T where T: Fn(&Path) -> anyhow::Result<CargoInfo> + Send + Sync {}
#[derive(Debug, Clone)]
pub struct CargoInfo {
pub crate_name: String,
pub target_dir: PathBuf,
}
pub fn cargo_info_provider() -> impl CargoInfoProvider {
let provider: &dyn CargoInfoProvider = &|cargo_manifest_path| {
let cargo_metadata = cargo_metadata::MetadataCommand::new()
.manifest_path(cargo_manifest_path)
.exec()
.context(format!(
"Failed to execute cargo metadata command. Manifest path: {}",
cargo_manifest_path.display()
))?;
let crate_name = cargo_metadata
.packages
.iter()
.find_map(|package| {
if package.manifest_path == cargo_manifest_path {
Some(package.name.to_string())
} else {
None
}
})
.context(format!(
"Failed to find crate name \"{}\" for cargo manifest path: {}",
cargo_manifest_path.display(),
cargo_manifest_path.display()
))?;
let target_dir = cargo_metadata.target_directory.into_std_path_buf();
Ok(CargoInfo {
crate_name,
target_dir,
})
};
provider
}