Skip to main content

ggen_cli_lib/cmds/
utils.rs

1//! Utils Commands - clap-noun-verb v3.4.0 Migration
2//!
3//! This module implements utility commands using the v3.4.0 #[verb] pattern.
4
5use clap_noun_verb::Result;
6use clap_noun_verb_macros::verb;
7use serde::Serialize;
8use std::collections::HashMap;
9
10// ============================================================================
11// Output Types
12// ============================================================================
13
14#[derive(Serialize)]
15struct DoctorOutput {
16    checks_passed: usize,
17    checks_failed: usize,
18    warnings: usize,
19    results: Vec<CheckResult>,
20    overall_status: String,
21}
22
23#[derive(Serialize)]
24struct CheckResult {
25    name: String,
26    status: String,
27    message: Option<String>,
28}
29
30#[derive(Serialize)]
31struct EnvOutput {
32    variables: HashMap<String, String>,
33    total: usize,
34}
35
36/// Output for setting environment variables
37#[derive(Serialize)]
38#[allow(dead_code)]
39struct EnvSetOutput {
40    key: String,
41    value: String,
42    success: bool,
43}
44
45// ============================================================================
46// Verb Functions
47// ============================================================================
48
49/// Run system diagnostics
50#[verb]
51fn doctor(all: bool, fix: bool, format: Option<String>) -> Result<DoctorOutput> {
52    let _ = fix; // reserved CLI flag; auto-fix not yet implemented
53    let format = format.unwrap_or_else(|| "table".to_string());
54    use ggen_core::domain::utils::{execute_doctor, DoctorInput};
55
56    let input = DoctorInput {
57        verbose: all,
58        check: None,
59        env: format == "env",
60    };
61
62    let result = crate::runtime::block_on(async move {
63        execute_doctor(input).await.map_err(|e| {
64            ggen_core::utils::error::Error::new(&format!("System diagnostics failed: {}", e))
65        })
66    })
67    .map_err(|e: ggen_core::utils::Error| {
68        clap_noun_verb::NounVerbError::execution_error(e.to_string())
69    })?
70    .map_err(|e: ggen_core::utils::Error| {
71        clap_noun_verb::NounVerbError::execution_error(e.to_string())
72    })?;
73
74    let results = result
75        .checks
76        .into_iter()
77        .map(|r| CheckResult {
78            name: r.name,
79            status: format!("{:?}", r.status),
80            message: Some(r.message),
81        })
82        .collect::<Vec<_>>();
83
84    let checks_passed = results.iter().filter(|r| r.status == "Ok").count();
85    let checks_failed = results.iter().filter(|r| r.status == "Error").count();
86    let warnings = results.iter().filter(|r| r.status == "Warning").count();
87
88    let overall_status = if checks_failed == 0 {
89        "healthy".to_string()
90    } else {
91        "needs attention".to_string()
92    };
93
94    Ok(DoctorOutput {
95        checks_passed,
96        checks_failed,
97        warnings,
98        results,
99        overall_status,
100    })
101}
102
103/// Manage environment variables
104#[verb]
105fn env(list: bool, get: Option<String>, set: Option<String>, system: bool) -> Result<EnvOutput> {
106    let _ = system; // reserved CLI flag; system-wide env scope not yet implemented
107    let variables = run_env(list, get.as_deref(), set.as_deref());
108    let total = variables.len();
109    Ok(EnvOutput { variables, total })
110}
111
112fn run_env(list: bool, get: Option<&str>, set: Option<&str>) -> HashMap<String, String> {
113    let mut variables = HashMap::new();
114
115    if let Some(key) = get {
116        if let Ok(value) = std::env::var(key) {
117            variables.insert(key.to_string(), value);
118        }
119    } else if let Some(kv) = set {
120        if let Some((key, value)) = kv.split_once('=') {
121            std::env::set_var(key, value);
122            variables.insert(key.to_string(), value.to_string());
123        }
124    }
125
126    if list || (get.is_none() && set.is_none()) {
127        collect_ggen_env_vars(&mut variables);
128    }
129
130    variables
131}
132
133fn collect_ggen_env_vars(vars: &mut HashMap<String, String>) {
134    for (key, value) in std::env::vars() {
135        if key.starts_with("GGEN_") || key.starts_with("RUST_") || key == "HOME" || key == "PATH" {
136            vars.insert(key, value);
137        }
138    }
139}