//! 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> { // 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> { // 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> { 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> { 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> { 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(()) } }