systemprompt_cloud/paths/
cloud.rs1use std::path::{Path, PathBuf};
2
3use crate::constants::{cli_session, credentials, dir_names, tenants};
4
5use super::resolve_path;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum CloudPath {
9 Credentials,
10 Tenants,
11 CliSession,
12 SessionsDir,
13}
14
15impl CloudPath {
16 #[must_use]
17 pub const fn default_filename(&self) -> &'static str {
18 match self {
19 Self::Credentials => credentials::DEFAULT_FILE_NAME,
20 Self::Tenants => tenants::DEFAULT_FILE_NAME,
21 Self::CliSession => cli_session::DEFAULT_FILE_NAME,
22 Self::SessionsDir => dir_names::SESSIONS,
23 }
24 }
25
26 #[must_use]
27 pub const fn default_dirname(&self) -> &'static str {
28 match self {
29 Self::Credentials => credentials::DEFAULT_DIR_NAME,
30 Self::Tenants => tenants::DEFAULT_DIR_NAME,
31 Self::CliSession | Self::SessionsDir => cli_session::DEFAULT_DIR_NAME,
32 }
33 }
34
35 #[must_use]
36 pub const fn is_dir(&self) -> bool {
37 matches!(self, Self::SessionsDir)
38 }
39}
40
41#[derive(Debug, Clone)]
42pub struct CloudPaths {
43 base_dir: PathBuf,
44 credentials_path: Option<PathBuf>,
45 tenants_path: Option<PathBuf>,
46}
47
48impl CloudPaths {
49 #[must_use]
50 pub fn new(profile_dir: &Path) -> Self {
51 Self {
52 base_dir: profile_dir.join(credentials::DEFAULT_DIR_NAME),
53 credentials_path: None,
54 tenants_path: None,
55 }
56 }
57
58 #[must_use]
59 pub fn from_config(
60 profile_dir: &Path,
61 credentials_path_str: &str,
62 tenants_path_str: &str,
63 ) -> Self {
64 let credentials_path = if credentials_path_str.is_empty() {
65 None
66 } else {
67 Some(resolve_path(profile_dir, credentials_path_str))
68 };
69
70 let tenants_path = if tenants_path_str.is_empty() {
71 None
72 } else {
73 Some(resolve_path(profile_dir, tenants_path_str))
74 };
75
76 let base_dir = credentials_path
77 .as_ref()
78 .and_then(|p| p.parent())
79 .map(PathBuf::from)
80 .unwrap_or_else(|| {
81 profile_dir
82 .ancestors()
83 .find(|p| p.file_name().is_some_and(|n| n == ".systemprompt"))
84 .map(PathBuf::from)
85 .unwrap_or_else(|| profile_dir.join(credentials::DEFAULT_DIR_NAME))
86 });
87
88 Self {
89 base_dir,
90 credentials_path,
91 tenants_path,
92 }
93 }
94
95 #[must_use]
96 pub fn resolve(&self, path: CloudPath) -> PathBuf {
97 match path {
98 CloudPath::Credentials => self
99 .credentials_path
100 .clone()
101 .unwrap_or_else(|| self.base_dir.join(credentials::DEFAULT_FILE_NAME)),
102 CloudPath::Tenants => self
103 .tenants_path
104 .clone()
105 .unwrap_or_else(|| self.base_dir.join(tenants::DEFAULT_FILE_NAME)),
106 CloudPath::CliSession => self.base_dir.join(cli_session::DEFAULT_FILE_NAME),
107 CloudPath::SessionsDir => self.base_dir.join(dir_names::SESSIONS),
108 }
109 }
110
111 #[must_use]
112 pub fn base_dir(&self) -> &Path {
113 &self.base_dir
114 }
115
116 #[must_use]
117 pub fn exists(&self, path: CloudPath) -> bool {
118 self.resolve(path).exists()
119 }
120}
121
122pub fn get_cloud_paths() -> anyhow::Result<CloudPaths> {
123 use systemprompt_models::profile_bootstrap::ProfileBootstrap;
124
125 if let Ok(profile) = ProfileBootstrap::get() {
126 if let Some(cloud_config) = &profile.cloud {
127 if let Ok(profile_path) = ProfileBootstrap::get_path() {
128 if let Some(profile_dir) = Path::new(profile_path).parent() {
129 return Ok(CloudPaths::from_config(
130 profile_dir,
131 &cloud_config.credentials_path,
132 &cloud_config.tenants_path,
133 ));
134 }
135 }
136 }
137 }
138
139 let cwd = std::env::current_dir()
140 .map_err(|e| anyhow::anyhow!("Failed to get current directory: {}", e))?;
141 Ok(CloudPaths::new(&cwd))
142}