use std::{
collections::BTreeMap,
env::{self, VarError},
process::Command,
};
use serde::Deserialize;
pub fn features_env(cargo: &str) {
#[derive(Deserialize)]
struct Config {
features: BTreeMap<String, Vec<String>>,
}
impl Config {
fn enabled_features(self) -> impl Iterator<Item = String> {
self.features
.into_keys()
.filter(|feature| feature != "default")
.filter(|feature| {
let feature = feature.replace('-', "_").to_uppercase();
env::var(format!("CARGO_FEATURE_{feature}")).is_ok()
})
}
}
let config: Config = toml::from_str(cargo).expect("should parse Cargo.toml");
let mut features = String::new();
for feature in config.enabled_features() {
if !features.is_empty() {
features.push(' ');
}
features.push_str(&format!("+{feature}"));
}
println!("cargo::rustc-env=CARGO_FEATURES={features}");
}
pub fn target_envs() {
forward_env("CARGO_CFG_TARGET_OS");
forward_env("CARGO_CFG_TARGET_ENV");
forward_env("CARGO_CFG_TARGET_ARCH");
}
pub fn git_envs() {
if try_forward_env("GIT_DESCRIBE").is_err() {
let description = git(&["describe", "--all", "--always"]);
println!("cargo::rustc-env=GIT_DESCRIBE={description}");
}
if try_forward_env("GIT_REV").is_err() {
let rev = git(&["rev-parse", "HEAD"]);
println!("cargo::rustc-env=GIT_REV={rev}");
}
}
fn git(args: &[&str]) -> String {
let output = Command::new("git")
.arg("--git-dir=.git")
.args(args)
.output();
match output {
Ok(output) if output.status.success() => {
String::from_utf8_lossy(&output.stdout).trim().to_owned()
}
_ => String::from("unknown"),
}
}
fn try_forward_env(key: &str) -> Result<String, VarError> {
let env = env::var(key);
if let Ok(val) = &env {
println!("cargo::rustc-env={key}={val}");
}
env
}
fn forward_env(key: &str) {
try_forward_env(key).unwrap_or_else(|_| panic!("should get env {key}"));
}