feat: Add ability to inspect build information and features at runtime

Also re-adds ability to inspect used features
This commit is contained in:
Jade Ellis
2026-01-20 21:01:21 +00:00
parent 108a4fe336
commit 16de2a2cc0
26 changed files with 317 additions and 4 deletions
+2 -1
View File
@@ -2,6 +2,7 @@
name = "conduwuit_build_metadata"
description.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true
@@ -27,6 +28,6 @@ crate-type = [
[build-dependencies]
built = { version = "0.8", features = [] }
cargo_metadata = { version = "0.23.1" }
[lints]
workspace = true
+81 -2
View File
@@ -1,5 +1,9 @@
use std::process::Command;
use std::{
collections::BTreeMap, env, fmt::Write as FmtWrite, fs, io::Write, path::Path,
process::Command,
};
use cargo_metadata::MetadataCommand;
fn run_git_command(args: &[&str]) -> Option<String> {
Command::new("git")
.args(args)
@@ -11,12 +15,60 @@ fn run_git_command(args: &[&str]) -> Option<String> {
.filter(|s| !s.is_empty())
}
fn get_env(env_var: &str) -> Option<String> {
match std::env::var(env_var) {
match env::var(env_var) {
| Ok(val) if !val.is_empty() => Some(val),
| _ => None,
}
}
fn main() {
println!("cargo:rerun-if-changed=Cargo.toml");
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); // Cargo.toml path
let manifest_path = Path::new(&manifest_dir).join("Cargo.toml");
let metadata = MetadataCommand::new()
.manifest_path(&manifest_path)
.no_deps()
.exec()
.expect("failed to parse `cargo metadata`");
let workspace_packages = metadata
.workspace_members
.iter()
.map(|package| {
let package = metadata.packages.iter().find(|p| p.id == *package).unwrap();
println!("cargo:rerun-if-changed={}", package.manifest_path.as_str());
package
})
.collect::<Vec<_>>();
// Extract available features from workspace packages
let mut available_features: BTreeMap<String, Vec<String>> = BTreeMap::new();
for package in &workspace_packages {
let crate_name = package
.name
.trim_start_matches("conduwuit-")
.replace('-', "_");
let features: Vec<String> = package.features.keys().cloned().collect();
if !features.is_empty() {
available_features.insert(crate_name, features);
}
}
// Generate Rust code for available features
let features_code = generate_features_code(&available_features);
let features_dst =
Path::new(&env::var("OUT_DIR").expect("OUT_DIR not set")).join("available_features.rs");
let mut features_file = fs::File::create(features_dst).unwrap();
features_file.write_all(features_code.as_bytes()).unwrap();
let dst = Path::new(&env::var("OUT_DIR").expect("OUT_DIR not set")).join("pkg.json");
let mut out_file = fs::File::create(dst).unwrap();
out_file
.write_all(format!("{workspace_packages:?}").as_bytes())
.unwrap();
// built gets the default crate from the workspace. Not sure if this is intended
// behavior, but it's what we want.
built::write_built_file().expect("Failed to acquire build-time information");
@@ -91,3 +143,30 @@ fn main() {
println!("cargo:rerun-if-env-changed=GIT_REMOTE_URL");
println!("cargo:rerun-if-env-changed=GIT_REMOTE_COMMIT_URL");
}
fn generate_features_code(features: &BTreeMap<String, Vec<String>>) -> String {
let mut code = String::from(
r#"
/// All available features for workspace crates
pub const WORKSPACE_FEATURES: &[(&str, &[&str])] = &[
"#,
);
for (crate_name, feature_list) in features {
write!(code, " (\"{crate_name}\", &[").unwrap();
for (i, feature) in feature_list.iter().enumerate() {
if i > 0 {
code.push_str(", ");
}
write!(code, "\"{feature}\"").unwrap();
}
code.push_str("]),\n");
}
code.push_str(
r#"];
"#,
);
code
}
+4
View File
@@ -2,6 +2,10 @@ pub mod built {
include!(concat!(env!("OUT_DIR"), "/built.rs"));
}
// Include generated available features
// This provides: pub const WORKSPACE_FEATURES: &[(&str, &[&str])]
include!(concat!(env!("OUT_DIR"), "/available_features.rs"));
pub static GIT_COMMIT_HASH: Option<&str> = option_env!("GIT_COMMIT_HASH");
pub static GIT_COMMIT_HASH_SHORT: Option<&str> = option_env!("GIT_COMMIT_HASH_SHORT");