-
-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
96 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,124 @@ | ||
use std::{collections::HashMap, env}; | ||
use std::{ | ||
collections::HashMap, | ||
env::{self, VarError}, | ||
}; | ||
|
||
use git2::{DescribeOptions, Repository}; | ||
use serde::Deserialize; | ||
|
||
fn main() { | ||
if let Ok(git) = Repository::open(".") { | ||
if let None = maybe_forward_env("GIT_DESCRIBE") { | ||
let mut opts = DescribeOptions::new(); | ||
opts.describe_all(); | ||
opts.show_commit_oid_as_fallback(true); | ||
|
||
let description = git | ||
.describe(&opts) | ||
.expect("should describe git object") | ||
.format(None) | ||
.expect("should format git object description"); | ||
|
||
println!("cargo::rustc-env=GIT_DESCRIBE={description}"); | ||
}; | ||
|
||
if let None = maybe_forward_env("GIT_REV") { | ||
let head = git.head().expect("should get git HEAD"); | ||
let commit = head.peel_to_commit().expect("should get git HEAD commit"); | ||
let rev = commit.id().to_string(); | ||
|
||
println!("cargo::rustc-env=GIT_REV={rev}"); | ||
}; | ||
features_env(); | ||
target_envs(); | ||
git_envs(); | ||
} | ||
|
||
/// Builds the `CARGO_FEATURES` environment variable. | ||
/// | ||
/// This function turns enabled cargo features into a simple string | ||
/// `+feature1 +feature2 +featureN`, which then exposes it via the | ||
/// `CARGO_FEATURES` environment variable. | ||
/// | ||
/// It first reads and parses the Cargo.toml in order to extract all | ||
/// available features (omitting "default"). It then checks for | ||
/// enabled features via `CARGO_FEATURE_<name>` to finally collect | ||
/// them into a string. | ||
fn features_env() { | ||
#[derive(Deserialize)] | ||
struct Config { | ||
features: HashMap<String, Vec<String>>, | ||
} | ||
|
||
let toml: CargoToml = | ||
toml::from_str(include_str!("./Cargo.toml")).expect("should read Cargo.toml"); | ||
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 mut features = String::new(); | ||
let config: Config = | ||
toml::from_str(include_str!("./Cargo.toml")).expect("should parse Cargo.toml"); | ||
|
||
for (feature, _) in toml.features { | ||
if feature == "default" { | ||
continue; | ||
} | ||
let mut features = String::new(); | ||
|
||
if feature_enabled(&feature) { | ||
for feature in config.enabled_features() { | ||
if !features.is_empty() { | ||
features.push(' '); | ||
features.push_str(&format!("+{feature}")); | ||
} | ||
features.push_str(&format!("+{feature}")); | ||
} | ||
|
||
println!("cargo::rustc-env=CARGO_FEATURES={features}"); | ||
} | ||
|
||
/// Builds environment variables related to the target platform. | ||
/// | ||
/// This function basically forwards existing cargo environments | ||
/// related to the target platform. | ||
fn target_envs() { | ||
forward_env("CARGO_CFG_TARGET_OS"); | ||
forward_env("CARGO_CFG_TARGET_ENV"); | ||
forward_env("CARGO_CFG_TARGET_ARCH"); | ||
} | ||
|
||
#[derive(Deserialize)] | ||
struct CargoToml { | ||
features: HashMap<String, Vec<String>>, | ||
/// Builds environment variables related to git. | ||
/// | ||
/// This function basically tries to forward existing git environment | ||
/// variables. In case of failure, it tries to build them using | ||
/// [`git2`]. | ||
fn git_envs() { | ||
// skip the process if the current directory is not a git | ||
// repository (for example, from a nix build root jail) | ||
let Ok(git) = Repository::open(".") else { | ||
return; | ||
}; | ||
|
||
if try_forward_env("GIT_DESCRIBE").is_err() { | ||
let mut opts = DescribeOptions::new(); | ||
opts.describe_all(); | ||
opts.show_commit_oid_as_fallback(true); | ||
|
||
let description = 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 head = git.head().expect("should get git HEAD"); | ||
let commit = head.peel_to_commit().expect("should get git HEAD commit"); | ||
let rev = commit.id().to_string(); | ||
|
||
println!("cargo::rustc-env=GIT_REV={rev}"); | ||
}; | ||
} | ||
|
||
fn feature_enabled(feature: &str) -> bool { | ||
let feature = feature.replace('-', "_").to_uppercase(); | ||
env::var(format!("CARGO_FEATURE_{feature}")).is_ok() | ||
} | ||
/// Tries to forward the given environment variable. | ||
/// | ||
/// For a more strict version, see [`forward_env`]. | ||
fn try_forward_env(key: &str) -> Result<String, VarError> { | ||
let env = env::var(key); | ||
|
||
fn maybe_forward_env(key: &str) -> Option<String> { | ||
match env::var(key) { | ||
Err(_) => None, | ||
Ok(val) => { | ||
println!("cargo::rustc-env={key}={val}"); | ||
Some(val) | ||
} | ||
if let Ok(val) = &env { | ||
println!("cargo::rustc-env={key}={val}"); | ||
} | ||
|
||
env | ||
} | ||
|
||
/// Forwards the given environment variable. | ||
/// | ||
/// This function panics in case the forward fails (when the | ||
/// environment variable does not exist for example). | ||
/// | ||
/// For a less strict version, see [`try_forward_env`]. | ||
fn forward_env(key: &str) { | ||
maybe_forward_env(key).expect(&format!("should get env {key}")); | ||
try_forward_env(key).expect(&format!("should get env {key}")); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters