1use std::{
8 collections::HashMap,
9 env::{self, VarError},
10};
11
12use git2::{DescribeOptions, Repository};
13use serde::Deserialize;
14
15pub fn features_env(cargo: &str) {
26 #[derive(Deserialize)]
27 struct Config {
28 features: HashMap<String, Vec<String>>,
29 }
30
31 impl Config {
32 fn enabled_features(self) -> impl Iterator<Item = String> {
33 self.features
34 .into_keys()
35 .filter(|feature| feature != "default")
36 .filter(|feature| {
37 let feature = feature.replace('-', "_").to_uppercase();
38 env::var(format!("CARGO_FEATURE_{feature}")).is_ok()
39 })
40 }
41 }
42
43 let config: Config = toml::from_str(cargo).expect("should parse Cargo.toml");
44
45 let mut features = String::new();
46
47 for feature in config.enabled_features() {
48 if !features.is_empty() {
49 features.push(' ');
50 }
51 features.push_str(&format!("+{feature}"));
52 }
53
54 println!("cargo::rustc-env=CARGO_FEATURES={features}");
55}
56
57pub fn target_envs() {
62 forward_env("CARGO_CFG_TARGET_OS");
63 forward_env("CARGO_CFG_TARGET_ENV");
64 forward_env("CARGO_CFG_TARGET_ARCH");
65}
66
67pub fn git_envs() {
73 let git = Repository::open(".").ok();
74
75 if try_forward_env("GIT_DESCRIBE").is_err() {
76 let description = match &git {
77 None => String::from("unknown"),
78 Some(git) => {
79 let mut opts = DescribeOptions::new();
80 opts.describe_all();
81 opts.show_commit_oid_as_fallback(true);
82
83 git.describe(&opts)
84 .expect("should describe git object")
85 .format(None)
86 .expect("should format git object description")
87 }
88 };
89
90 println!("cargo::rustc-env=GIT_DESCRIBE={description}");
91 };
92
93 if try_forward_env("GIT_REV").is_err() {
94 let rev = match &git {
95 None => String::from("unknown"),
96 Some(git) => {
97 let head = git.head().expect("should get git HEAD");
98 let commit = head.peel_to_commit().expect("should get git HEAD commit");
99 commit.id().to_string()
100 }
101 };
102
103 println!("cargo::rustc-env=GIT_REV={rev}");
104 };
105}
106
107fn try_forward_env(key: &str) -> Result<String, VarError> {
111 let env = env::var(key);
112
113 if let Ok(val) = &env {
114 println!("cargo::rustc-env={key}={val}");
115 }
116
117 env
118}
119
120fn forward_env(key: &str) {
127 try_forward_env(key).unwrap_or_else(|_| panic!("should get env {key}"));
128}