use std::{
collections::HashMap,
env::{self, VarError},
};
use git2::{DescribeOptions, Repository};
use serde::Deserialize;
pub fn features_env(cargo: &str) {
#[derive(Deserialize)]
struct Config {
features: HashMap<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() {
let git = Repository::open(".").ok();
if try_forward_env("GIT_DESCRIBE").is_err() {
let description = match &git {
None => String::from("unknown"),
Some(git) => {
let mut opts = DescribeOptions::new();
opts.describe_all();
opts.show_commit_oid_as_fallback(true);
git.describe(&opts)
.expect("should describe git object")
.format(None)
.expect("should format git object description")
}
};
println!("cargo::rustc-env=GIT_DESCRIBE={description}");
};
if try_forward_env("GIT_REV").is_err() {
let rev = match &git {
None => String::from("unknown"),
Some(git) => {
let head = git.head().expect("should get git HEAD");
let commit = head.peel_to_commit().expect("should get git HEAD commit");
commit.id().to_string()
}
};
println!("cargo::rustc-env=GIT_REV={rev}");
};
}
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).expect(&format!("should get env {key}"));
}