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