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