use anyhow::{Context, Result};
use cargo_metadata::{Metadata, MetadataCommand, Package};
use std::{collections::HashMap, path::Path};
use crate::builder_error::BuilderError;
#[derive(Debug, Default)]
pub struct CrateInfo {
pub name: String,
pub snake_case_name: String,
pub version: String,
pub features: HashMap<String, Vec<String>>,
}
impl CrateInfo {
pub fn from_manifest(manifest_path: &Path) -> Result<Self> {
anyhow::ensure!(
manifest_path.exists(),
BuilderError::InvalidManifestPath(manifest_path.to_path_buf())
);
let mut meta_cmd = MetadataCommand::new();
let metadata = meta_cmd
.manifest_path(manifest_path)
.exec()
.context("unable to invoke `cargo metadata`")?;
let root_package = Self::root_package(&metadata)
.ok_or_else(|| BuilderError::RootPackageNotFound.into())
.and_then(Self::check)?;
let name = root_package.name.clone();
let snake_case_name = name.replace('-', "_");
let version = root_package.version.to_string();
let features = root_package.features.clone();
Ok(Self {
name,
snake_case_name,
version,
features,
})
}
fn root_package(metadata: &Metadata) -> Option<&Package> {
let root_id = metadata.resolve.as_ref()?.root.as_ref()?;
metadata
.packages
.iter()
.find(|package| package.id == *root_id)
}
fn check(pkg: &Package) -> Result<&Package> {
let validated_lib = |ty: &String| ty == "lib" || ty == "rlib";
let _ = pkg
.targets
.iter()
.find(|target| {
target.name.eq(&pkg.name) && target.crate_types.iter().any(validated_lib)
})
.ok_or(BuilderError::InvalidCrateType)?;
Ok(pkg)
}
}