robin/config/
robin_config.rs1use std::collections::HashMap;
2use std::fs;
3use std::path::Path;
4use serde::{Deserialize, Serialize};
5use anyhow::{Context, Result};
6use serde_json::Value;
7
8#[derive(Debug, Serialize, Deserialize)]
9pub struct RobinConfig {
10 #[serde(default)]
11 pub include: Vec<String>,
12 pub scripts: HashMap<String, Value>,
13}
14
15impl RobinConfig {
16 pub fn load(path: &Path) -> Result<Self> {
17 if !path.exists() {
18 return Err(anyhow::anyhow!("No .robin.json found. Run 'robin init' first"));
19 }
20
21 let content = fs::read_to_string(path)
22 .with_context(|| format!("Failed to read config file: {}", path.display()))?;
23
24 let mut config: Self = serde_json::from_str(&content)
25 .with_context(|| "The .robin.json file exists but contains malformed JSON. Please check the file format.")?;
26
27 if !config.include.is_empty() {
29 let base_dir = path.parent().unwrap_or_else(|| Path::new("."));
30 config = config.merge_includes(base_dir)?;
31 }
32
33 Ok(config)
34 }
35
36 fn merge_includes(&self, base_dir: &Path) -> Result<Self> {
37 let mut merged_scripts = self.scripts.clone();
38
39 for include_path in &self.include {
40 let full_path = base_dir.join(include_path);
41 let included_config = Self::load(&full_path)
42 .with_context(|| format!("Failed to load included config: {}", include_path))?;
43
44 for (key, value) in included_config.scripts {
46 if !merged_scripts.contains_key(&key) {
47 merged_scripts.insert(key, value);
48 }
49 }
50 }
51
52 Ok(Self {
53 include: self.include.clone(),
54 scripts: merged_scripts,
55 })
56 }
57
58 pub fn save(&self, path: &Path) -> Result<()> {
59 let content = serde_json::to_string_pretty(self)
60 .with_context(|| "Failed to serialize config")?;
61
62 fs::write(path, content)
63 .with_context(|| format!("Failed to write config to: {}", path.display()))?;
64
65 Ok(())
66 }
67
68 pub fn create_template() -> Self {
69 let mut scripts = HashMap::new();
70 scripts.insert("clean".to_string(), Value::String("...".to_string()));
71 scripts.insert("deploy staging".to_string(), Value::String("echo 'ruby deploy tool --staging'".to_string()));
72 scripts.insert("deploy production".to_string(), Value::String("...".to_string()));
73 scripts.insert("release beta".to_string(), Value::String("...".to_string()));
74 scripts.insert("release alpha".to_string(), Value::String("...".to_string()));
75 scripts.insert("release dev".to_string(), Value::String("...".to_string()));
76
77 Self {
78 include: Vec::new(),
79 scripts
80 }
81 }
82}