use clap_noun_verb::Result;
use clap_noun_verb_macros::verb;
use serde::Serialize;
use std::collections::HashMap;
#[derive(Serialize)]
struct DoctorOutput {
checks_passed: usize,
checks_failed: usize,
warnings: usize,
results: Vec<CheckResult>,
overall_status: String,
}
#[derive(Serialize)]
struct CheckResult {
name: String,
status: String,
message: Option<String>,
}
#[derive(Serialize)]
struct EnvOutput {
variables: HashMap<String, String>,
total: usize,
}
#[derive(Serialize)]
#[allow(dead_code)]
struct EnvSetOutput {
key: String,
value: String,
success: bool,
}
#[verb]
fn doctor(all: bool, fix: bool, format: Option<String>) -> Result<DoctorOutput> {
let _ = fix; let format = format.unwrap_or_else(|| "table".to_string());
use ggen_core::domain::utils::{execute_doctor, DoctorInput};
let input = DoctorInput {
verbose: all,
check: None,
env: format == "env",
};
let result = crate::runtime::block_on(async move {
execute_doctor(input).await.map_err(|e| {
ggen_core::utils::error::Error::new(&format!("System diagnostics failed: {}", e))
})
})
.map_err(|e: ggen_core::utils::Error| {
clap_noun_verb::NounVerbError::execution_error(e.to_string())
})?
.map_err(|e: ggen_core::utils::Error| {
clap_noun_verb::NounVerbError::execution_error(e.to_string())
})?;
let results = result
.checks
.into_iter()
.map(|r| CheckResult {
name: r.name,
status: format!("{:?}", r.status),
message: Some(r.message),
})
.collect::<Vec<_>>();
let checks_passed = results.iter().filter(|r| r.status == "Ok").count();
let checks_failed = results.iter().filter(|r| r.status == "Error").count();
let warnings = results.iter().filter(|r| r.status == "Warning").count();
let overall_status = if checks_failed == 0 {
"healthy".to_string()
} else {
"needs attention".to_string()
};
Ok(DoctorOutput {
checks_passed,
checks_failed,
warnings,
results,
overall_status,
})
}
#[verb]
fn env(list: bool, get: Option<String>, set: Option<String>, system: bool) -> Result<EnvOutput> {
let _ = system; let variables = run_env(list, get.as_deref(), set.as_deref());
let total = variables.len();
Ok(EnvOutput { variables, total })
}
fn run_env(list: bool, get: Option<&str>, set: Option<&str>) -> HashMap<String, String> {
let mut variables = HashMap::new();
if let Some(key) = get {
if let Ok(value) = std::env::var(key) {
variables.insert(key.to_string(), value);
}
} else if let Some(kv) = set {
if let Some((key, value)) = kv.split_once('=') {
std::env::set_var(key, value);
variables.insert(key.to_string(), value.to_string());
}
}
if list || (get.is_none() && set.is_none()) {
collect_ggen_env_vars(&mut variables);
}
variables
}
fn collect_ggen_env_vars(vars: &mut HashMap<String, String>) {
for (key, value) in std::env::vars() {
if key.starts_with("GGEN_") || key.starts_with("RUST_") || key == "HOME" || key == "PATH" {
vars.insert(key, value);
}
}
}