#[cfg(test)]
mod tests;
mod workspace;
pub use workspace::{decode_workspace_root, workspace_root_command};
pub use cargo_metadata as schema;
use super::selection::{CargoFeatureSelection, graph_arguments};
use std::{ffi::OsString, path::Path, process::Command};
pub fn decode_metadata(bytes: &[u8]) -> Result<schema::Metadata, serde_json::Error> {
serde_json::from_slice(bytes)
}
pub struct CargoMetadataSpec<'a> {
pub manifest_path: &'a Path,
pub include_dependencies: bool,
pub filter_platform: Option<&'a str>,
pub locked: bool,
pub offline: bool,
pub features: &'a CargoFeatureSelection,
}
pub struct CargoTreeSpec<'a> {
pub manifest_path: &'a Path,
pub packages: &'a [&'a str],
pub target: &'a str,
pub edges: &'a str,
pub format: &'a str,
pub locked: bool,
pub offline: bool,
pub features: &'a CargoFeatureSelection,
}
impl CargoMetadataSpec<'_> {
pub fn command(&self, mut command: Command) -> std::io::Result<Command> {
command.args(metadata_arguments(
self.include_dependencies,
self.filter_platform,
));
configure(
&mut command,
self.manifest_path,
self.locked,
self.offline,
self.features,
)?;
Ok(command)
}
}
pub(crate) fn metadata_arguments(
include_dependencies: bool,
filter_platform: Option<&str>,
) -> Vec<OsString> {
let mut arguments = vec!["metadata".into(), "--format-version=1".into()];
if !include_dependencies {
arguments.push("--no-deps".into());
}
if let Some(target) = filter_platform {
arguments.extend(["--filter-platform".into(), target.into()]);
}
arguments
}
impl CargoTreeSpec<'_> {
pub fn command(&self, mut command: Command) -> std::io::Result<Command> {
if self.packages.is_empty() || self.packages.iter().any(|package| package.is_empty()) {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Cargo tree requires nonempty package selectors",
));
}
command.args([
"tree",
"--color",
"never",
"--target",
self.target,
"--edges",
self.edges,
"--prefix",
"depth",
"--no-dedupe",
"--charset",
"ascii",
"--format",
self.format,
]);
configure(
&mut command,
self.manifest_path,
self.locked,
self.offline,
self.features,
)?;
for package in self.packages {
command.arg("--package").arg(package);
}
Ok(command)
}
}
fn configure(
command: &mut Command,
manifest: &Path,
locked: bool,
offline: bool,
features: &CargoFeatureSelection,
) -> std::io::Result<()> {
let manifest = if manifest.is_absolute() {
manifest.to_path_buf()
} else {
std::env::current_dir()?.join(manifest)
};
command.current_dir(manifest.parent().unwrap_or_else(|| Path::new(".")));
command.arg("--manifest-path").arg(manifest);
command.args(graph_arguments(features, locked, offline));
Ok(())
}