config_commands/
config_commands.rs1use std::{
4 fs, io,
5 path::PathBuf,
6 time::{SystemTime, UNIX_EPOCH},
7};
8
9use clap::{Parser, Subcommand};
10use confique::Config;
11use rust_config_tree::{
12 ConfigSchema,
13 cli::{ConfigCommand, handle_config_command},
14 config::load_config,
15};
16use schemars::JsonSchema;
17
18#[derive(Debug, Parser)]
19#[command(name = "config-commands")]
20struct Cli {
21 #[arg(long)]
22 config: Option<PathBuf>,
23
24 #[command(subcommand)]
25 command: Option<Command>,
26}
27
28#[derive(Debug, Subcommand)]
29enum Command {
30 Run,
31
32 #[command(flatten)]
34 Config(ConfigCommand),
35}
36
37#[derive(Debug, Config, JsonSchema, ConfigSchema)]
38pub struct AppConfig {
39 #[config(default = [])]
40 pub include: Vec<PathBuf>,
41
42 #[config(default = "demo")]
43 pub mode: String,
44
45 #[config(nested)]
46 pub server: ServerConfig,
47}
48
49#[derive(Debug, Config, JsonSchema)]
50pub struct ServerConfig {
51 #[config(default = "127.0.0.1")]
52 pub bind: String,
53
54 #[config(default = 8080)]
55 pub port: u16,
56}
57
58fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
60 let cli = Cli::parse();
61 let config_path = match &cli.config {
62 Some(path) => path.clone(),
63 None => write_demo_config()?,
64 };
65
66 match cli.command.unwrap_or(Command::Run) {
67 Command::Run => {
68 let config = load_config::<AppConfig>(&config_path)?;
69 println!("config path: {}", config_path.display());
70 println!("include count: {}", config.include.len());
71 println!("mode: {}", config.mode);
72 println!("server bind: {}", config.server.bind);
73 println!("server port: {}", config.server.port);
74 }
75 Command::Config(command) => {
76 handle_config_command::<Cli, AppConfig>(command, &config_path)?;
77 }
78 }
79
80 Ok(())
81}
82
83fn write_demo_config() -> io::Result<PathBuf> {
85 let dir = temp_example_dir("config-commands")?;
86 let root_config = dir.join("config.yaml");
87
88 fs::write(
89 &root_config,
90 r#"
91mode: local
92server:
93 bind: 0.0.0.0
94 port: 3000
95"#
96 .trim_start(),
97 )?;
98
99 Ok(root_config)
100}
101
102fn temp_example_dir(name: &str) -> io::Result<PathBuf> {
104 let nanos = SystemTime::now()
105 .duration_since(UNIX_EPOCH)
106 .unwrap_or_default()
107 .as_nanos();
108 let dir = std::env::temp_dir().join(format!("rust-config-tree-{name}-{nanos}"));
109 fs::create_dir_all(&dir)?;
110 Ok(dir)
111}