Skip to main content

gor/cmd/
config.rs

1//! Implementation of the `gor config` subcommand.
2//!
3//! Manages configuration values stored in `~/.config/gor/config.yml`.
4
5#![allow(clippy::print_stdout)]
6
7use crate::cli::ConfigCommand;
8use crate::config::{self, GorConfig};
9
10/// Run the `gor config` subcommand.
11///
12/// # Errors
13///
14/// Returns an error if the config file cannot be read or written, or if the
15/// user provides an invalid key or value.
16pub fn run(cmd: ConfigCommand, hostname: Option<&str>) -> anyhow::Result<()> {
17    match cmd {
18        ConfigCommand::Get { key } => {
19            let config = config::load()?;
20            match config::get(&config, &key, hostname) {
21                Some(value) => {
22                    // Print scalar values as plain strings, complex values as YAML.
23                    if let Some(s) = value.as_str() {
24                        println!("{s}");
25                    } else {
26                        let yaml = serde_yaml_ng::to_string(value).unwrap_or_default();
27                        print!("{yaml}");
28                    }
29                }
30                None => {
31                    anyhow::bail!("config key '{key}' is not set");
32                }
33            }
34        }
35        ConfigCommand::Set { key, value } => {
36            config::validate(&key, &value).map_err(|e| anyhow::anyhow!("{e}"))?;
37            let mut config = config::load()?;
38            config::set(
39                &mut config,
40                &key,
41                serde_yaml_ng::Value::String(value.clone()),
42                hostname,
43            );
44            config::save(&config)?;
45            if let Some(h) = hostname {
46                println!("Set '{key}' to '{value}' for host '{h}'");
47            } else {
48                println!("Set '{key}' to '{value}'");
49            }
50        }
51        ConfigCommand::List => {
52            let config = config::load()?;
53            print_config(&config, hostname);
54        }
55    }
56    Ok(())
57}
58
59/// Print the current configuration as YAML to stdout.
60fn print_config(config: &GorConfig, hostname: Option<&str>) {
61    if let Some(h) = hostname {
62        if let Some(host_config) = config.hosts.get(h) {
63            if host_config.is_empty() {
64                println!("# No host-scoped config for '{h}'");
65            } else {
66                let wrapper = serde_yaml_ng::Value::Mapping(
67                    host_config
68                        .iter()
69                        .map(|(k, v)| (serde_yaml_ng::Value::String(k.clone()), v.clone()))
70                        .collect(),
71                );
72                let yaml = serde_yaml_ng::to_string(&wrapper).unwrap_or_default();
73                print!("{yaml}");
74            }
75        } else {
76            println!("# No host-scoped config for '{h}'");
77        }
78    } else {
79        // Print global config. If empty, print a comment.
80        if config.global.is_empty() && config.hosts.is_empty() {
81            println!("# No configuration set");
82        } else {
83            let yaml = serde_yaml_ng::to_string(config).unwrap_or_default();
84            print!("{yaml}");
85        }
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn print_config_empty() {
95        let config = GorConfig::default();
96        // Should not panic.
97        print_config(&config, None);
98    }
99
100    #[test]
101    fn print_config_with_global() {
102        let mut config = GorConfig::default();
103        config.global.insert(
104            "editor".to_string(),
105            serde_yaml_ng::Value::String("vim".to_string()),
106        );
107        print_config(&config, None);
108    }
109
110    #[test]
111    fn print_config_host_scoped() {
112        let mut config = GorConfig::default();
113        config.hosts.insert(
114            "github.com".to_string(),
115            std::collections::BTreeMap::from([(
116                "editor".to_string(),
117                serde_yaml_ng::Value::String("code".to_string()),
118            )]),
119        );
120        print_config(&config, Some("github.com"));
121    }
122}