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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#![deny(missing_docs)]
use std::collections::BTreeSet;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use toml;
pub fn setup_feature_groups() {
let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
path.push("Cargo.toml");
let cargo_toml = path.as_path();
let mut cargo_file = File::open(cargo_toml).unwrap();
let mut content = String::new();
cargo_file.read_to_string(&mut content).unwrap();
let value = content.parse::<toml::Value>().unwrap();
let feature_groups = value
.get("package")
.and_then(|d| d.get("metadata"))
.and_then(|d| d.get("feature_groups"));
let features: BTreeSet<String> = env::vars()
.into_iter()
.filter(|(k, _v)| k.starts_with("CARGO_FEATURE"))
.map(|(k, _v)| to_feature_name(k))
.collect();
if let Some(toml::Value::Table(table)) = feature_groups {
process_feature_groups(table, &features)
}
env::vars()
.into_iter()
.filter(|(k, _v)| k.starts_with("CARGO_FEATURE"))
.for_each(|(k, _)| println!("cargo:rerun-if-env-changed={}", k));
}
fn to_feature_name(s: String) -> String {
s.replace("CARGO_FEATURE_", "").to_lowercase()
}
fn process_feature_groups(
groups: &toml::value::Table,
defined_features: &BTreeSet<String>,
) {
groups.into_iter().for_each(|(k, v)| {
if let toml::Value::Array(group_features) = v {
process_feature_group(k, &group_features, defined_features)
} else {
panic!("Feature group should be defined as array of features!, invalid group {}: {:?}", k, v);
}
});
}
fn process_feature_group(
group_name: &str,
group_features: &Vec<toml::Value>,
defined_features: &BTreeSet<String>,
) {
let mut defined = false;
for group_feature in group_features.iter() {
if let toml::Value::String(gf) = group_feature {
let this_defined = defined_features.contains(gf);
if defined && this_defined {
panic!(
"Multiple options defined for feature group {}!",
group_name
);
}
if this_defined {
defined = this_defined;
println!("cargo:rustc-cfg={}=\"{}\"", group_name, gf);
}
} else {
panic!("Invalid definition of {} feature group; features should be strings, found: {:?}",
group_name, group_feature)
}
}
if !defined {
panic!("No features defined for feature group {}!", group_name)
}
}