systemprompt_cli/commands/admin/config/
paths.rs1use anyhow::Result;
9use clap::Subcommand;
10use std::path::Path;
11use systemprompt_config::ProfileBootstrap;
12use systemprompt_logging::CliService;
13use systemprompt_models::Profile;
14
15use super::types::{PathInfo, PathValidation, PathsConfigOutput, PathsValidateOutput};
16use crate::CliConfig;
17use crate::cli_settings::OutputFormat;
18use crate::shared::{CommandOutput, render_result};
19
20#[derive(Debug, Clone, Copy, Subcommand)]
21pub enum PathsCommands {
22 #[command(about = "Show paths configuration", alias = "list")]
23 Show,
24
25 #[command(about = "Validate that all configured paths exist")]
26 Validate,
27}
28
29pub fn execute(command: PathsCommands, config: &CliConfig) -> Result<()> {
30 match command {
31 PathsCommands::Show => execute_show(config),
32 PathsCommands::Validate => execute_validate(config),
33 }
34}
35
36pub(super) fn execute_show(config: &CliConfig) -> Result<()> {
37 let profile = ProfileBootstrap::get()?;
38
39 let output = PathsConfigOutput {
40 system: PathInfo {
41 path: profile.paths.system.clone(),
42 exists: Path::new(&profile.paths.system).exists(),
43 },
44 services: PathInfo {
45 path: profile.paths.services.clone(),
46 exists: Path::new(&profile.paths.services).exists(),
47 },
48 bin: PathInfo {
49 path: profile.paths.bin.clone(),
50 exists: Path::new(&profile.paths.bin).exists(),
51 },
52 web_path: profile.paths.web_path.as_ref().map(|p| PathInfo {
53 path: p.clone(),
54 exists: Path::new(p).exists(),
55 }),
56 storage: profile.paths.storage.as_ref().map(|p| PathInfo {
57 path: p.clone(),
58 exists: Path::new(p).exists(),
59 }),
60 geoip_database: profile.paths.geoip_database.as_ref().map(|p| PathInfo {
61 path: p.clone(),
62 exists: Path::new(p).exists(),
63 }),
64 };
65
66 render_result(
67 &CommandOutput::card_value("Paths Configuration", &output),
68 config,
69 );
70
71 Ok(())
72}
73
74pub(super) fn execute_validate(config: &CliConfig) -> Result<()> {
75 let profile = ProfileBootstrap::get()?;
76
77 let validations = collect_path_validations(profile);
78 let valid = validations.iter().filter(|v| v.required).all(|v| v.exists);
79
80 let output = PathsValidateOutput {
81 valid,
82 paths: validations,
83 };
84
85 render_result(
86 &CommandOutput::table_of(vec!["name", "path", "exists", "required"], &output.paths)
87 .with_title("Paths Validation"),
88 config,
89 );
90
91 if config.output_format() == OutputFormat::Table {
92 if valid {
93 CliService::success("All required paths exist");
94 } else {
95 CliService::error("Some required paths are missing");
96 }
97 }
98
99 Ok(())
100}
101
102fn collect_path_validations(profile: &Profile) -> Vec<PathValidation> {
103 let mut validations = vec![
104 path_validation("system", &profile.paths.system, true),
105 path_validation("services", &profile.paths.services, true),
106 path_validation("bin", &profile.paths.bin, true),
107 ];
108
109 if let Some(web_path) = &profile.paths.web_path {
110 validations.push(path_validation("web_path", web_path, false));
111 }
112
113 if let Some(storage) = &profile.paths.storage {
114 validations.push(path_validation("storage", storage, false));
115 }
116
117 if let Some(geoip) = &profile.paths.geoip_database {
118 validations.push(path_validation("geoip_database", geoip, false));
119 }
120
121 validations.push(path_validation("config", &profile.paths.config(), false));
122 validations.push(path_validation(
123 "ai_config",
124 &profile.paths.ai_config(),
125 false,
126 ));
127 validations.push(path_validation(
128 "content_config",
129 &profile.paths.content_config(),
130 false,
131 ));
132
133 validations
134}
135
136fn path_validation(name: &str, path: &str, required: bool) -> PathValidation {
137 PathValidation {
138 name: name.to_owned(),
139 path: path.to_owned(),
140 exists: Path::new(path).exists(),
141 required,
142 }
143}