Skip to main content

systemprompt_cloud/paths/
cloud.rs

1use 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}