232 lines
8.7 KiB
Rust
Raw Normal View History

//! Build script template demonstrating configuration traits usage
//!
//! This build script shows how to use Rustelo's configuration traits
//! to generate compile-time constants and build artifacts.
use rustelo_core_types::traits_config::*;
use std::env;
use std::path::{Path, PathBuf};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
// Get build environment
let out_dir = env::var("OUT_DIR")?;
let manifest_dir = env::var("CARGO_MANIFEST_DIR")?;
let project_root = Path::new(&manifest_dir);
println!("cargo:rerun-if-changed=config");
println!("cargo:rerun-if-changed=config.toml");
println!("cargo:rerun-if-changed=.env");
// Example 1: Using a custom configuration resolver
generate_config_with_custom_resolver(&project_root, &out_dir)?;
// Example 2: Generate environment-specific constants
generate_environment_constants(&project_root, &out_dir)?;
// Example 3: Feature-based configuration
generate_feature_constants(&project_root, &out_dir)?;
println!("cargo:warning=Configuration build completed successfully");
Ok(())
}
/// Example of using a custom configuration resolver with traits
fn generate_config_with_custom_resolver(
project_root: &Path,
out_dir: &str
) -> Result<(), Box<dyn Error>> {
// This would use your custom resolver implementation
// For this example, we'll create a simple resolver
let config = ExampleConfig {
server_host: env::var("SERVER_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()),
server_port: env::var("SERVER_PORT")
.unwrap_or_else(|_| "3030".to_string())
.parse()
.unwrap_or(3030),
content_path: env::var("SITE_CONTENT_PATH")
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from("content")),
debug_mode: env::var("DEBUG")
.unwrap_or_else(|_| "true".to_string())
.parse()
.unwrap_or(true),
};
// Generate WASM constants using trait
let resolver = ExampleResolver;
let constants = resolver.generate_constants(&config);
let out_path = Path::new(out_dir).join("server_config_constants.rs");
resolver.write_constants_file(&constants, &out_path)?;
println!("cargo:warning=Generated server config constants at: {}", out_path.display());
Ok(())
}
/// Generate environment-specific constants
fn generate_environment_constants(
project_root: &Path,
out_dir: &str
) -> Result<(), Box<dyn Error>> {
let environment = env::var("RUSTELO_ENV").unwrap_or_else(|_| "development".to_string());
let mut constants = WasmConstants::new();
constants.add_string("BUILD_ENVIRONMENT", environment.clone());
constants.add_string("BUILD_TIMESTAMP", chrono::Utc::now().to_rfc3339());
constants.add_boolean("IS_PRODUCTION", environment == "production");
constants.add_boolean("IS_DEVELOPMENT", environment == "development");
// Add environment-specific settings
match environment.as_str() {
"production" => {
constants.add_boolean("ENABLE_DEBUG_LOGS", false);
constants.add_boolean("ENABLE_PERFORMANCE_METRICS", true);
constants.add_numeric("LOG_LEVEL", 2); // WARN
}
"development" => {
constants.add_boolean("ENABLE_DEBUG_LOGS", true);
constants.add_boolean("ENABLE_PERFORMANCE_METRICS", false);
constants.add_numeric("LOG_LEVEL", 0); // DEBUG
}
"staging" => {
constants.add_boolean("ENABLE_DEBUG_LOGS", true);
constants.add_boolean("ENABLE_PERFORMANCE_METRICS", true);
constants.add_numeric("LOG_LEVEL", 1); // INFO
}
_ => {
constants.add_boolean("ENABLE_DEBUG_LOGS", true);
constants.add_boolean("ENABLE_PERFORMANCE_METRICS", false);
constants.add_numeric("LOG_LEVEL", 0); // DEBUG
}
}
let code = constants.generate_rust_code();
let out_path = Path::new(out_dir).join("environment_constants.rs");
std::fs::write(&out_path, code)?;
println!("cargo:warning=Generated environment constants for '{}' at: {}", environment, out_path.display());
Ok(())
}
/// Generate feature-based constants
fn generate_feature_constants(
project_root: &Path,
out_dir: &str
) -> Result<(), Box<dyn Error>> {
let mut constants = WasmConstants::new();
// Check which Cargo features are enabled and generate corresponding constants
constants.add_boolean("FEATURE_AUTH", cfg!(feature = "auth"));
constants.add_boolean("FEATURE_CONTENT_DB", cfg!(feature = "content-db"));
constants.add_boolean("FEATURE_EMAIL", cfg!(feature = "email"));
constants.add_boolean("FEATURE_TLS", cfg!(feature = "tls"));
constants.add_boolean("FEATURE_METRICS", cfg!(feature = "metrics"));
constants.add_boolean("FEATURE_CRYPTO", cfg!(feature = "crypto"));
// Add feature-specific configuration
if cfg!(feature = "auth") {
constants.add_string("AUTH_JWT_ALGORITHM", "HS256");
constants.add_numeric("AUTH_TOKEN_EXPIRY_HOURS", 24);
}
if cfg!(feature = "content-db") {
constants.add_string("CONTENT_STORAGE_TYPE", "database");
} else {
constants.add_string("CONTENT_STORAGE_TYPE", "filesystem");
}
if cfg!(feature = "metrics") {
constants.add_string("METRICS_ENDPOINT", "/metrics");
constants.add_boolean("METRICS_ENABLED", true);
}
// Add build-time feature detection functions
let mut feature_code = constants.generate_rust_code();
feature_code.push_str("\n// Feature detection functions\n");
feature_code.push_str("pub fn has_auth_feature() -> bool { FEATURE_AUTH }\n");
feature_code.push_str("pub fn has_database_content() -> bool { FEATURE_CONTENT_DB }\n");
feature_code.push_str("pub fn has_email_feature() -> bool { FEATURE_EMAIL }\n");
feature_code.push_str("pub fn has_tls_feature() -> bool { FEATURE_TLS }\n");
feature_code.push_str("pub fn has_metrics_feature() -> bool { FEATURE_METRICS }\n");
feature_code.push_str("pub fn has_crypto_feature() -> bool { FEATURE_CRYPTO }\n");
feature_code.push_str("\n// Runtime feature configuration\n");
feature_code.push_str("pub fn get_enabled_features() -> Vec<&'static str> {\n");
feature_code.push_str(" let mut features = Vec::new();\n");
feature_code.push_str(" if FEATURE_AUTH { features.push(\"auth\"); }\n");
feature_code.push_str(" if FEATURE_CONTENT_DB { features.push(\"content-db\"); }\n");
feature_code.push_str(" if FEATURE_EMAIL { features.push(\"email\"); }\n");
feature_code.push_str(" if FEATURE_TLS { features.push(\"tls\"); }\n");
feature_code.push_str(" if FEATURE_METRICS { features.push(\"metrics\"); }\n");
feature_code.push_str(" if FEATURE_CRYPTO { features.push(\"crypto\"); }\n");
feature_code.push_str(" features\n");
feature_code.push_str("}\n");
let out_path = Path::new(out_dir).join("feature_constants.rs");
std::fs::write(&out_path, feature_code)?;
println!("cargo:warning=Generated feature constants at: {}", out_path.display());
Ok(())
}
/// Example configuration structure
#[derive(Debug, Clone)]
struct ExampleConfig {
server_host: String,
server_port: u16,
content_path: PathBuf,
debug_mode: bool,
}
/// Example resolver implementation
struct ExampleResolver;
impl WasmConstantGenerator for ExampleResolver {
type Config = ExampleConfig;
fn generate_constants(&self, config: &Self::Config) -> WasmConstants {
let mut constants = WasmConstants::new();
constants.add_string("SERVER_HOST", &config.server_host);
constants.add_numeric("SERVER_PORT", config.server_port as i64);
constants.add_path("CONTENT_PATH", config.content_path.clone());
constants.add_boolean("DEBUG_MODE", config.debug_mode);
// Add derived constants
constants.add_string("SERVER_URL",
format!("http://{}:{}", config.server_host, config.server_port));
constants
}
fn write_constants_file(
&self,
constants: &WasmConstants,
out_path: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
let mut code = constants.generate_rust_code();
// Add convenience functions
code.push_str("\n// Convenience functions\n");
code.push_str("pub fn get_server_url() -> String {\n");
code.push_str(" format!(\"http://{}:{}\", SERVER_HOST, SERVER_PORT)\n");
code.push_str("}\n\n");
code.push_str("pub fn is_debug_build() -> bool {\n");
code.push_str(" DEBUG_MODE\n");
code.push_str("}\n\n");
code.push_str("pub fn get_content_path() -> &'static str {\n");
code.push_str(" CONTENT_PATH\n");
code.push_str("}\n");
std::fs::write(out_path, code)?;
Ok(())
}
}