use spicex::Spice;
use std::fs;
use tempfile::TempDir;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Spice Configuration File Discovery Example ===\n");
let temp_dir = TempDir::new()?;
let config_dir = temp_dir.path().join("config");
fs::create_dir_all(&config_dir)?;
create_sample_configs(&config_dir)?;
println!("1. Basic File Discovery:");
basic_file_discovery(&config_dir)?;
println!("\n2. Multiple Search Paths:");
multiple_search_paths(&temp_dir)?;
println!("\n3. Automatic Configuration Loading:");
automatic_loading(&config_dir)?;
println!("\n4. Merging Multiple Configuration Files:");
merge_configurations(&config_dir)?;
println!("\n5. Handling Missing Files:");
handle_missing_files()?;
println!("\n=== Example completed successfully! ===");
Ok(())
}
fn create_sample_configs(config_dir: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
let json_config = r#"{
"app": {
"name": "MyApp",
"version": "1.0.0",
"debug": true
},
"database": {
"host": "localhost",
"port": 5432,
"name": "myapp_db"
},
"features": ["auth", "logging"]
}"#;
fs::write(config_dir.join("app.json"), json_config)?;
let yaml_config = r#"app:
name: MyApp
version: 1.0.0
debug: false # Different from JSON
environment: production # Only in YAML
database:
host: localhost
port: 5432
name: myapp_db
ssl: true # Only in YAML
server:
port: 8080
timeout: 30
"#;
fs::write(config_dir.join("app.yaml"), yaml_config)?;
let toml_config = r#"[app]
name = "MyApp"
version = "1.0.0"
debug = true
[database]
host = "localhost"
port = 5432
name = "myapp_db"
[cache]
enabled = true
ttl = 3600
"#;
fs::write(config_dir.join("app.toml"), toml_config)?;
println!("Created sample configuration files:");
println!(" - {}/app.json", config_dir.display());
println!(" - {}/app.yaml", config_dir.display());
println!(" - {}/app.toml", config_dir.display());
Ok(())
}
fn basic_file_discovery(config_dir: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
let mut spice_instance = Spice::new();
spice_instance.set_config_name("app");
spice_instance.add_config_path(config_dir);
match spice_instance.find_config_file()? {
Some(config_file) => {
println!(" Found config file: {}", config_file.display());
spice_instance.read_in_config()?;
if let Some(app_name) = spice_instance.get_string("app.name")? {
println!(" App name: {}", app_name);
}
if let Some(debug) = spice_instance.get_bool("app.debug")? {
println!(" Debug mode: {}", debug);
}
}
None => {
println!(" No configuration file found");
}
}
Ok(())
}
fn multiple_search_paths(temp_dir: &TempDir) -> Result<(), Box<dyn std::error::Error>> {
let config_dir1 = temp_dir.path().join("config1");
let config_dir2 = temp_dir.path().join("config2");
fs::create_dir_all(&config_dir1)?;
fs::create_dir_all(&config_dir2)?;
let high_priority_config = r#"{"priority": "high", "source": "config1"}"#;
let low_priority_config = r#"{"priority": "low", "source": "config2"}"#;
fs::write(config_dir1.join("priority.json"), high_priority_config)?;
fs::write(config_dir2.join("priority.json"), low_priority_config)?;
let mut spice_instance = Spice::new();
spice_instance.set_config_name("priority");
spice_instance.add_config_path(&config_dir1); spice_instance.add_config_path(&config_dir2);
spice_instance.read_in_config()?;
if let Some(source) = spice_instance.get_string("source")? {
println!(" Configuration loaded from: {}", source);
println!(" (Should be 'config1' due to search path priority)");
}
Ok(())
}
fn automatic_loading(config_dir: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
let mut spice_instance = Spice::new();
spice_instance.set_config_name("app");
spice_instance.add_config_path(config_dir);
match spice_instance.read_in_config() {
Ok(()) => {
println!(" Configuration loaded successfully!");
if let Some(db_host) = spice_instance.get_string("database.host")? {
println!(" Database host: {}", db_host);
}
if let Some(db_port) = spice_instance.get_i64("database.port")? {
println!(" Database port: {}", db_port);
}
}
Err(e) => {
println!(" Failed to load configuration: {}", e);
}
}
Ok(())
}
fn merge_configurations(config_dir: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
let mut spice_instance = Spice::new();
spice_instance.set_config_name("app");
spice_instance.add_config_path(config_dir);
let merged_count = spice_instance.merge_in_config()?;
println!(" Merged {} configuration files", merged_count);
println!(" Values from merged configuration:");
if let Some(app_name) = spice_instance.get_string("app.name")? {
println!(" App name: {}", app_name);
}
if let Some(environment) = spice_instance.get_string("app.environment")? {
println!(" Environment: {} (from YAML)", environment);
}
if let Some(ssl) = spice_instance.get_bool("database.ssl")? {
println!(" Database SSL: {} (from YAML)", ssl);
}
if let Some(cache_enabled) = spice_instance.get_bool("cache.enabled")? {
println!(" Cache enabled: {} (from TOML)", cache_enabled);
}
let all_keys = spice_instance.all_keys();
println!(" Total configuration keys: {}", all_keys.len());
Ok(())
}
fn handle_missing_files() -> Result<(), Box<dyn std::error::Error>> {
let mut spice_instance = Spice::new();
spice_instance.set_config_name("nonexistent");
spice_instance.add_config_path("/nonexistent/path");
match spice_instance.read_in_config() {
Ok(()) => {
println!(" Unexpectedly found configuration!");
}
Err(e) => {
println!(" Gracefully handled missing file: {}", e);
}
}
match spice_instance.find_config_file()? {
Some(path) => {
println!(" Unexpectedly found file: {}", path.display());
}
None => {
println!(" Correctly returned None for missing configuration");
}
}
Ok(())
}