systemprompt_models/profile/
paths.rs1use serde::{Deserialize, Serialize};
2use std::path::{Path, PathBuf};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct PathsConfig {
6 pub system: String,
7 pub services: String,
8 pub bin: String,
9
10 #[serde(default)]
11 pub web_path: Option<String>,
12
13 #[serde(default)]
14 pub storage: Option<String>,
15
16 #[serde(default)]
17 pub geoip_database: Option<String>,
18}
19
20impl PathsConfig {
21 pub fn resolve_relative_to(&mut self, base: &Path) {
22 self.system = resolve_path(base, &self.system);
23 self.services = resolve_path(base, &self.services);
24 self.bin = resolve_path(base, &self.bin);
25 self.storage = self.storage.as_ref().map(|p| resolve_path(base, p));
26 self.geoip_database = self.geoip_database.as_ref().map(|p| resolve_path(base, p));
27 self.web_path = self.web_path.as_ref().map(|p| resolve_path(base, p));
28 }
29
30 pub fn skills(&self) -> String {
31 format!("{}/skills", self.services)
32 }
33
34 pub fn config(&self) -> String {
35 format!("{}/config/config.yaml", self.services)
36 }
37
38 pub fn ai_config(&self) -> String {
39 format!("{}/ai/config.yaml", self.services)
40 }
41
42 pub fn content_config(&self) -> String {
43 format!("{}/content/config.yaml", self.services)
44 }
45
46 pub fn web_config(&self) -> String {
47 format!("{}/web/config.yaml", self.services)
48 }
49
50 pub fn web_metadata(&self) -> String {
51 format!("{}/web/metadata.yaml", self.services)
52 }
53
54 pub fn web_path_resolved(&self) -> String {
55 self.web_path
56 .clone()
57 .unwrap_or_else(|| format!("{}/web", self.system))
58 }
59
60 pub fn storage_resolved(&self) -> Option<&str> {
61 self.storage.as_deref()
62 }
63
64 pub fn geoip_database_resolved(&self) -> Option<&str> {
65 self.geoip_database.as_deref()
66 }
67}
68
69pub fn resolve_path(base: &Path, path: &str) -> String {
70 let p = Path::new(path);
71 if p.is_absolute() {
72 path.to_string()
73 } else {
74 let resolved = base.join(p);
75 resolved.canonicalize().map_or_else(
76 |_| resolved.to_string_lossy().to_string(),
77 |canonical| canonical.to_string_lossy().to_string(),
78 )
79 }
80}
81
82pub fn expand_home(path_str: &str) -> PathBuf {
83 path_str.strip_prefix("~/").map_or_else(
84 || PathBuf::from(path_str),
85 |stripped| {
86 let home = std::env::var("HOME")
87 .or_else(|_| std::env::var("USERPROFILE"))
88 .unwrap_or_else(|_| {
89 tracing::warn!(
90 path = %path_str,
91 "Cannot expand ~/ path: neither HOME nor USERPROFILE is set"
92 );
93 String::new()
94 });
95 PathBuf::from(home).join(stripped)
96 },
97 )
98}
99
100pub fn resolve_with_home(base: &Path, path_str: &str) -> PathBuf {
101 let path = expand_home(path_str);
102
103 if path.is_absolute() {
104 path
105 } else {
106 base.join(path)
107 }
108}