use std::path::{Path, PathBuf};
use std::process::Stdio;
use tokio::process::Command;
pub struct Metadata(serde_json::Value);
impl Metadata {
pub async fn workspace() -> Option<Self> {
Self::run(&["--no-deps"]).await
}
pub async fn full() -> Option<Self> {
Self::run(&[]).await
}
async fn run(extra_args: &[&str]) -> Option<Self> {
let output = Command::new("cargo")
.args(["metadata", "--format-version=1"])
.args(extra_args)
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()
.ok()?
.wait_with_output()
.await
.ok()?;
if !output.status.success() {
return None;
}
serde_json::from_slice(&output.stdout).ok().map(Self)
}
pub fn target_dir(&self) -> Option<PathBuf> {
self.0["target_directory"].as_str().map(PathBuf::from)
}
pub fn workspace_root(&self) -> Option<PathBuf> {
self.0["workspace_root"].as_str().map(PathBuf::from)
}
pub fn local_package_dirs(&self) -> Vec<PathBuf> {
self.0["packages"]
.as_array()
.into_iter()
.flatten()
.filter(|package| package["source"].is_null())
.filter_map(|package| {
let manifest = Path::new(package["manifest_path"].as_str()?);
Some(manifest.parent()?.to_path_buf())
})
.collect()
}
}