use std::env; use std::fs; use std::path::Path; use std::process::Command; fn run_command(cmd: &str, args: &[&str]) -> Option { let output = Command::new(cmd).args(args).output().ok()?; if output.status.success() { let s = String::from_utf8_lossy(&output.stdout).trim().to_string(); if !s.is_empty() { return Some(s); } } None } fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("plugins_gen.rs"); // Read the plugins directory let plugins_dir = Path::new("plugins"); let mut plugins_code = String::new(); let mut registry_add_code = String::new(); if plugins_dir.exists() { for entry in fs::read_dir(plugins_dir).unwrap() { let entry = entry.unwrap(); let path = entry.path(); if path.extension().and_then(|s| s.to_str()) == Some("rs") { let stem = path.file_stem().unwrap().to_str().unwrap(); // We'll use include! macro to include the file content directly. // However, `include!` requires a valid path. The generated file is in OUT_DIR, // so we need an absolute path or relative to the generated file. let abs_path = path.canonicalize().unwrap(); let abs_path_str = abs_path.to_str().unwrap(); plugins_code.push_str(&format!( "pub mod {} {{\n include!({:?});\n}}\n", stem, abs_path_str )); registry_add_code.push_str(&format!( "registry.push(Box::new({}::PluginImpl));\n", stem )); } } } let full_code = format!( " {} pub fn get_plugins() -> Vec> {{ let mut registry: Vec> = Vec::new(); {} registry }} ", plugins_code, registry_add_code ); fs::write(&dest_path, full_code).unwrap(); println!("cargo:rerun-if-changed=plugins"); // Add build metadata for versioning let version = env::var("CARGO_PKG_VERSION").unwrap_or_else(|_| "0.1.0".to_string()); let build_time = run_command("date", &["-u", "+%Y-%m-%d %H:%M:%S UTC"]) .unwrap_or_else(|| "Unknown".to_string()); let git_commit = run_command("git", &["rev-parse", "--short", "HEAD"]) .unwrap_or_else(|| "Unknown".to_string()); let target = env::var("TARGET").unwrap_or_else(|_| "Unknown".to_string()); let profile = env::var("PROFILE").unwrap_or_else(|_| "Unknown".to_string()); let rustc_path = env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string()); let rustc_version = run_command(&rustc_path, &["--version"]) .map(|s| s.split('\n').next().unwrap_or("").to_string()) .unwrap_or_else(|| "Unknown".to_string()); let version_string = format!( "{}\nbuild-time: {}\ncommit: {}\ntarget: {}\nprofile: {}\nrustc: {}", version, build_time, git_commit, target, profile, rustc_version ); let version_path = Path::new(&out_dir).join("version.txt"); fs::write(&version_path, &version_string).unwrap(); }