orbiton/commands/
config.rs

1// Configuration management command
2
3use anyhow::Result;
4use clap::{Args, Subcommand};
5use console::style;
6use std::path::PathBuf;
7
8use crate::config::OrbitonConfig;
9
10#[derive(Args)]
11pub struct ConfigArgs {
12    #[command(subcommand)]
13    command: ConfigCommand,
14}
15
16#[derive(Subcommand)]
17enum ConfigCommand {
18    /// Show current configuration
19    Show {
20        /// Project directory
21        #[arg(short, long)]
22        dir: Option<PathBuf>,
23    },
24    /// Create a default configuration file
25    Init {
26        /// Project directory
27        #[arg(short, long)]
28        dir: Option<PathBuf>,
29    },
30    /// Validate configuration
31    Validate {
32        /// Project directory
33        #[arg(short, long)]
34        dir: Option<PathBuf>,
35    },
36}
37
38pub fn execute(args: ConfigArgs) -> Result<()> {
39    match args.command {
40        ConfigCommand::Show { dir } => show_config(dir),
41        ConfigCommand::Init { dir } => init_config(dir),
42        ConfigCommand::Validate { dir } => validate_config(dir),
43    }
44}
45
46fn get_project_dir(dir: Option<PathBuf>) -> Result<PathBuf> {
47    match dir {
48        Some(d) => Ok(d),
49        None => std::env::current_dir()
50            .map_err(|e| anyhow::anyhow!("Failed to get current directory: {}", e)),
51    }
52}
53
54fn show_config(dir: Option<PathBuf>) -> Result<()> {
55    let project_dir = get_project_dir(dir)?;
56
57    println!(
58        "{} configuration for project at {project_dir:?}",
59        style("Showing").bold().blue()
60    );
61
62    let config = OrbitonConfig::load_from_project(&project_dir)?;
63
64    println!("\n{}", style("Project Configuration:").bold().underlined());
65    println!(
66        "  Source directory: {}",
67        style(&config.project.src_dir).cyan()
68    );
69    println!(
70        "  Output directory: {}",
71        style(&config.project.dist_dir).cyan()
72    );
73    println!(
74        "  Entry point: {}",
75        style(&config.project.entry_point).cyan()
76    );
77
78    println!("\n{}", style("Development Server:").bold().underlined());
79    println!("  Port: {}", style(config.dev_server.port).cyan());
80    println!("  Host: {}", style(&config.dev_server.host).cyan());
81    println!(
82        "  Auto-open browser: {}",
83        style(config.dev_server.auto_open).cyan()
84    );
85
86    println!("\n{}", style("Hot Module Reload:").bold().underlined());
87    println!("  Enabled: {}", style(config.hmr.enabled).cyan());
88    println!(
89        "  Debounce time: {}ms",
90        style(config.hmr.debounce_ms).cyan()
91    );
92    println!(
93        "  Preserve state: {}",
94        style(config.hmr.preserve_state).cyan()
95    );
96    println!("  Max retries: {}", style(config.hmr.max_retries).cyan());
97
98    println!("\n{}", style("Build Configuration:").bold().underlined());
99    println!(
100        "  Use beta toolchain: {}",
101        style(config.build.use_beta_toolchain).cyan()
102    );
103    println!("  Release mode: {}", style(config.build.release).cyan());
104    if let Some(target) = &config.build.target {
105        println!("  Target: {}", style(target).cyan());
106    }
107
108    println!("\n{}", style("Lint Configuration:").bold().underlined());
109    println!("  Enabled: {}", style(config.lint.enabled).cyan());
110
111    Ok(())
112}
113
114fn init_config(dir: Option<PathBuf>) -> Result<()> {
115    let project_dir = get_project_dir(dir)?;
116
117    println!(
118        "{} default configuration in {project_dir:?}",
119        style("Creating").bold().green()
120    );
121
122    let config_path = OrbitonConfig::create_default_config(&project_dir)?;
123
124    println!(
125        "{} Configuration file created at: {}",
126        style("Success!").bold().green(),
127        style(config_path.display()).cyan()
128    );
129
130    println!("\nYou can now customize the configuration by editing the .orbiton.toml file.");
131
132    Ok(())
133}
134
135fn validate_config(dir: Option<PathBuf>) -> Result<()> {
136    let project_dir = get_project_dir(dir)?;
137
138    println!(
139        "{} configuration for project at {project_dir:?}",
140        style("Validating").bold().yellow()
141    );
142
143    let config = OrbitonConfig::load_from_project(&project_dir)?;
144
145    match config.validate() {
146        Ok(()) => {
147            println!(
148                "{} Configuration is valid!",
149                style("Success!").bold().green()
150            );
151        }
152        Err(e) => {
153            println!(
154                "{} Configuration validation failed:",
155                style("Error:").bold().red()
156            );
157            println!("  {e}");
158            return Err(e);
159        }
160    }
161
162    Ok(())
163}
164
165#[cfg(test)]
166mod tests {
167    use super::*;
168    use tempfile::tempdir;
169
170    #[test]
171    fn test_config_init() {
172        let temp_dir = tempdir().unwrap();
173        let result = init_config(Some(temp_dir.path().to_path_buf()));
174        assert!(result.is_ok());
175
176        let config_path = temp_dir.path().join(".orbiton.toml");
177        assert!(config_path.exists());
178    }
179
180    #[test]
181    fn test_config_validate() {
182        let temp_dir = tempdir().unwrap();
183
184        // First create a config
185        let _ = init_config(Some(temp_dir.path().to_path_buf()));
186
187        // Then validate it
188        let result = validate_config(Some(temp_dir.path().to_path_buf()));
189        assert!(result.is_ok());
190    }
191}