use anyhow::Result;
use clap::Subcommand;
use std::path::Path;
use systemprompt_logging::CliService;
use systemprompt_models::ProfileBootstrap;
use super::types::{PathInfo, PathValidation, PathsConfigOutput, PathsValidateOutput};
use crate::CliConfig;
use crate::cli_settings::OutputFormat;
use crate::shared::{CommandResult, render_result};
#[derive(Debug, Clone, Copy, Subcommand)]
pub enum PathsCommands {
#[command(about = "Show paths configuration")]
Show,
#[command(about = "Validate that all configured paths exist")]
Validate,
}
pub fn execute(command: PathsCommands, config: &CliConfig) -> Result<()> {
match command {
PathsCommands::Show => execute_show(),
PathsCommands::Validate => execute_validate(config),
}
}
fn execute_show() -> Result<()> {
let profile = ProfileBootstrap::get()?;
let output = PathsConfigOutput {
system: PathInfo {
path: profile.paths.system.clone(),
exists: Path::new(&profile.paths.system).exists(),
},
services: PathInfo {
path: profile.paths.services.clone(),
exists: Path::new(&profile.paths.services).exists(),
},
bin: PathInfo {
path: profile.paths.bin.clone(),
exists: Path::new(&profile.paths.bin).exists(),
},
web_path: profile.paths.web_path.as_ref().map(|p| PathInfo {
path: p.clone(),
exists: Path::new(p).exists(),
}),
storage: profile.paths.storage.as_ref().map(|p| PathInfo {
path: p.clone(),
exists: Path::new(p).exists(),
}),
geoip_database: profile.paths.geoip_database.as_ref().map(|p| PathInfo {
path: p.clone(),
exists: Path::new(p).exists(),
}),
};
render_result(&CommandResult::card(output).with_title("Paths Configuration"));
Ok(())
}
fn execute_validate(config: &CliConfig) -> Result<()> {
let profile = ProfileBootstrap::get()?;
let mut validations: Vec<PathValidation> = Vec::new();
validations.push(PathValidation {
name: "system".to_string(),
path: profile.paths.system.clone(),
exists: Path::new(&profile.paths.system).exists(),
required: true,
});
validations.push(PathValidation {
name: "services".to_string(),
path: profile.paths.services.clone(),
exists: Path::new(&profile.paths.services).exists(),
required: true,
});
validations.push(PathValidation {
name: "bin".to_string(),
path: profile.paths.bin.clone(),
exists: Path::new(&profile.paths.bin).exists(),
required: true,
});
if let Some(web_path) = &profile.paths.web_path {
validations.push(PathValidation {
name: "web_path".to_string(),
path: web_path.clone(),
exists: Path::new(web_path).exists(),
required: false,
});
}
if let Some(storage) = &profile.paths.storage {
validations.push(PathValidation {
name: "storage".to_string(),
path: storage.clone(),
exists: Path::new(storage).exists(),
required: false,
});
}
if let Some(geoip) = &profile.paths.geoip_database {
validations.push(PathValidation {
name: "geoip_database".to_string(),
path: geoip.clone(),
exists: Path::new(geoip).exists(),
required: false,
});
}
let config_path = profile.paths.config();
validations.push(PathValidation {
name: "config".to_string(),
path: config_path.clone(),
exists: Path::new(&config_path).exists(),
required: false,
});
let ai_config_path = profile.paths.ai_config();
validations.push(PathValidation {
name: "ai_config".to_string(),
path: ai_config_path.clone(),
exists: Path::new(&ai_config_path).exists(),
required: false,
});
let content_config_path = profile.paths.content_config();
validations.push(PathValidation {
name: "content_config".to_string(),
path: content_config_path.clone(),
exists: Path::new(&content_config_path).exists(),
required: false,
});
let valid = validations.iter().filter(|v| v.required).all(|v| v.exists);
let output = PathsValidateOutput {
valid,
paths: validations,
};
render_result(&CommandResult::table(output).with_title("Paths Validation"));
if config.output_format() == OutputFormat::Table {
if valid {
CliService::success("All required paths exist");
} else {
CliService::error("Some required paths are missing");
}
}
Ok(())
}