use cargo_metadata::{Metadata, MetadataCommand};
use miniz_oxide::deflate::compress_to_vec_zlib;
use std::str::from_utf8;
use crate::{
auditable_from_metadata::encode_audit_data, cargo_arguments::CargoArgs,
rustc_arguments::RustcArgs, sbom_precursor,
};
pub fn compressed_dependency_list(rustc_args: &RustcArgs, target_triple: &str) -> Vec<u8> {
let sbom_path = std::env::var_os("CARGO_SBOM_PATH");
let version_info = if sbom_path.as_ref().map(|p| !p.is_empty()).unwrap_or(false) {
let sbom_path = std::env::split_paths(&sbom_path.unwrap()).next().unwrap();
let sbom_data: Vec<u8> = std::fs::read(&sbom_path)
.unwrap_or_else(|_| panic!("Failed to read SBOM file at {}", sbom_path.display()));
let sbom_precursor: sbom_precursor::SbomPrecursor = serde_json::from_slice(&sbom_data)
.unwrap_or_else(|_| panic!("Failed to parse SBOM file at {}", sbom_path.display()));
sbom_precursor.into()
} else {
let metadata = get_metadata(rustc_args, target_triple);
encode_audit_data(&metadata).unwrap()
};
let json = serde_json::to_string(&version_info).unwrap();
let compressed_json = compress_to_vec_zlib(json.as_bytes(), 7);
compressed_json
}
fn get_metadata(args: &RustcArgs, target_triple: &str) -> Metadata {
let mut metadata_command = MetadataCommand::new();
if let Some(path) = std::env::var_os("CARGO") {
metadata_command.cargo_path(path);
}
let manifest_dir = std::env::var_os("CARGO_MANIFEST_DIR").unwrap();
metadata_command.current_dir(manifest_dir);
let mut features = args.enabled_features();
if let Some(index) = features.iter().position(|x| x == &"default") {
features.remove(index);
} else {
metadata_command.features(cargo_metadata::CargoOpt::NoDefaultFeatures);
}
let owned_features: Vec<String> = features.iter().map(|s| s.to_string()).collect();
metadata_command.features(cargo_metadata::CargoOpt::SomeFeatures(owned_features));
let mut other_args = vec!["--filter-platform".to_owned(), target_triple.to_owned()];
let orig_args = CargoArgs::from_env()
.expect("Env var 'CARGO_AUDITABLE_ORIG_ARGS' set by 'cargo-auditable' is unset!");
if orig_args.offline {
other_args.push("--offline".to_owned());
}
if orig_args.frozen {
other_args.push("--frozen".to_owned());
}
if orig_args.locked {
other_args.push("--locked".to_owned());
}
for arg in orig_args.config {
other_args.push("--config".to_owned());
other_args.push(arg);
}
metadata_command.other_options(other_args);
let mut metadata_command = metadata_command.cargo_command();
metadata_command.env_remove("RUSTC_WORKSPACE_WRAPPER");
let output = metadata_command.output().unwrap();
if !output.status.success() {
panic!(
"cargo metadata failure: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let stdout = from_utf8(&output.stdout)
.expect("cargo metadata output not utf8")
.lines()
.find(|line| line.starts_with('{'))
.expect("cargo metadata output not json");
MetadataCommand::parse(stdout).expect("failed to parse cargo metadata output")
}