1#![forbid(unsafe_code)]
2
3use std::{env, path::{Path, PathBuf}, fs::File, io::Write};
9use std::{convert::TryFrom, collections::HashSet};
10use auditable_serde::VersionInfo;
11use miniz_oxide::deflate::compress_to_vec_zlib;
12use cargo_metadata::{Metadata, MetadataCommand};
13
14pub fn collect_dependency_list() {
16 let version_info = VersionInfo::try_from(&get_metadata()).unwrap();
17 let json = serde_json::to_string(&version_info).unwrap();
18 let compressed_json = compress_to_vec_zlib(json.as_bytes(), choose_compression_level());
19 let output_file_path = output_file_path();
20 write_dependency_info(&compressed_json, &output_file_path);
21 export_dependency_file_path(&output_file_path);
22}
23
24fn output_file_path() -> std::path::PathBuf {
25 let out_dir = env::var("OUT_DIR").unwrap();
26 let dest_dir = Path::new(&out_dir);
27 dest_dir.join("dependency-list.json.zlib")
28}
29
30fn write_dependency_info(data: &[u8], path: &Path) {
31 let f = File::create(path).unwrap();
32 let mut writer = std::io::BufWriter::new(f);
33 writer.write_all(data).unwrap();
34}
35
36fn export_dependency_file_path(path: &Path) {
37 println!("cargo:rustc-env=RUST_AUDIT_DEPENDENCY_FILE_LOCATION={}", path.display());
41}
42
43fn choose_compression_level() -> u8 {
44 let build_profile = env::var("PROFILE").unwrap();
45 match build_profile.as_str() {
46 "debug" => 1,
47 "release" => 7, _ => panic!("Unknown build profile: {}", &build_profile)
49 }
50}
51
52fn get_metadata() -> Metadata {
53 let mut metadata_command = metadata_command();
54 let mut features = enabled_features();
55 if let Some(index) = features.iter().position(|x| x.as_str() == "default") {
57 features.remove(index);
58 } else {
59 metadata_command.features(cargo_metadata::CargoOpt::NoDefaultFeatures);
60 }
61 metadata_command.features(cargo_metadata::CargoOpt::SomeFeatures(features));
62 metadata_command.exec().unwrap()
63}
64
65fn metadata_command() -> MetadataCommand {
66 let mut cmd = MetadataCommand::new();
69 let cargo_toml_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml");
70 cmd.manifest_path(cargo_toml_path);
71 cmd.other_options(vec!["--filter-platform=".to_owned() + &env::var("TARGET").unwrap()]);
72 cmd
73}
74
75fn enabled_features() -> Vec<String> {
76 let mut result = Vec::new();
77 let enabled_uppercase_features = enabled_uppercase_features();
83 let dry_run_metadata = metadata_command().exec().unwrap();
84 let root_package_id = dry_run_metadata.resolve.unwrap().root.unwrap();
87 let root_package = dry_run_metadata.packages.iter().filter(|p| p.id == root_package_id).next().unwrap();
88 for (feature, _implied_features) in root_package.features.iter() {
89 let mangled_feature = feature.to_ascii_uppercase().replace("-", "_");
90 if enabled_uppercase_features.contains(&mangled_feature) {
91 result.push(feature.clone());
92 }
93 }
94 result
95}
96
97fn enabled_uppercase_features() -> HashSet<String> {
98 let mut features = HashSet::new();
99 for (var_name, _value) in env::vars().filter(|(name, _value)| {
100 name.len() > "CARGO_FEATURE_".len() && name.starts_with("CARGO_FEATURE_")
101 }) {
102 features.insert(var_name.strip_prefix("CARGO_FEATURE_").unwrap().to_owned());
103 }
104 features
105}