use std::path::Path;
use cargo_metadata::camino::Utf8PathBuf;
use crate::error::Error;
fn utf8_path_replace(path: &Utf8PathBuf, left: &str, right: &str) -> Utf8PathBuf {
Utf8PathBuf::from(path.to_string().replace(left, right))
}
#[derive(Clone, Debug, PartialEq)]
pub struct Metadata {
pub inner: cargo_metadata::Package,
}
impl Metadata {
pub fn from_cargo_metadata<P: AsRef<Path>>(
mut md: cargo_metadata::Package,
root: P,
path_in_vcs: Option<&str>,
) -> Self {
let root_str = {
let mut temp = root.as_ref().to_path_buf();
if let Some(path_in_vcs) = path_in_vcs {
temp.push(path_in_vcs);
}
temp.push("");
temp.to_string_lossy().to_string()
};
md.manifest_path = utf8_path_replace(&md.manifest_path, &root_str, "");
for target in &mut md.targets {
target.src_path = utf8_path_replace(&target.src_path, &root_str, "");
}
Metadata { inner: md }
}
}
fn load_metadata_from_path<P: AsRef<Path>>(path: P) -> Result<cargo_metadata::Metadata, Error> {
cargo_metadata::MetadataCommand::new()
.manifest_path(path.as_ref())
.no_deps()
.other_options(vec![String::from("--offline")])
.exec()
.map_err(|err| Error::Metadata { inner: err.to_string() })
}
pub fn get_crate_metadata<P: AsRef<Path>>(root: P) -> Result<Metadata, Error> {
let path = root.as_ref().join("Cargo.toml");
let md = load_metadata_from_path(path)?;
let [package]: [cargo_metadata::Package; 1] =
md.packages
.into_iter()
.collect::<Vec<_>>()
.try_into()
.map_err(|_| Error::Metadata {
inner: String::from("Failed to load crate metadata (too many workspace members)."),
})?;
Ok(Metadata::from_cargo_metadata(package, root, None))
}
pub fn get_crate_metadata_from_workspace<P: AsRef<Path>>(
root: P,
path_in_vcs: &str,
name: &str,
) -> Result<Metadata, Error> {
let path = root.as_ref().join(path_in_vcs).join("Cargo.toml");
let md = load_metadata_from_path(path)?;
let [package]: [cargo_metadata::Package; 1] = md
.packages
.into_iter()
.filter(|p| p.name.as_ref() == name)
.collect::<Vec<_>>()
.try_into()
.map_err(|_| Error::Metadata {
inner: format!(
"Failed to load crate metadata (name does not match any workspace member): {}",
name.to_owned()
),
})?;
Ok(Metadata::from_cargo_metadata(package, root, Some(path_in_vcs)))
}