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::{ProjectContext, 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_project_context(ctx: &ProjectContext) -> Self {
60        Self {
61            base_dir: ctx.systemprompt_dir(),
62            credentials_path: Some(ctx.local_credentials()),
63            tenants_path: Some(ctx.local_tenants()),
64        }
65    }
66
67    #[must_use]
68    pub fn from_config(
69        profile_dir: &Path,
70        credentials_path_str: &str,
71        tenants_path_str: &str,
72    ) -> Self {
73        let credentials_path = if credentials_path_str.is_empty() {
74            None
75        } else {
76            Some(resolve_path(profile_dir, credentials_path_str))
77        };
78
79        let tenants_path = if tenants_path_str.is_empty() {
80            None
81        } else {
82            Some(resolve_path(profile_dir, tenants_path_str))
83        };
84
85        let base_dir = credentials_path
86            .as_ref()
87            .and_then(|p| p.parent())
88            .map_or_else(
89                || {
90                    profile_dir
91                        .ancestors()
92                        .find(|p| p.file_name().is_some_and(|n| n == ".systemprompt"))
93                        .map_or_else(
94                            || profile_dir.join(credentials::DEFAULT_DIR_NAME),
95                            PathBuf::from,
96                        )
97                },
98                PathBuf::from,
99            );
100
101        Self {
102            base_dir,
103            credentials_path,
104            tenants_path,
105        }
106    }
107
108    #[must_use]
109    pub fn resolve(&self, path: CloudPath) -> PathBuf {
110        match path {
111            CloudPath::Credentials => self
112                .credentials_path
113                .clone()
114                .unwrap_or_else(|| self.base_dir.join(credentials::DEFAULT_FILE_NAME)),
115            CloudPath::Tenants => self
116                .tenants_path
117                .clone()
118                .unwrap_or_else(|| self.base_dir.join(tenants::DEFAULT_FILE_NAME)),
119            CloudPath::CliSession => self.base_dir.join(cli_session::DEFAULT_FILE_NAME),
120            CloudPath::SessionsDir => self.base_dir.join(dir_names::SESSIONS),
121        }
122    }
123
124    #[must_use]
125    pub fn base_dir(&self) -> &Path {
126        &self.base_dir
127    }
128
129    #[must_use]
130    pub fn exists(&self, path: CloudPath) -> bool {
131        self.resolve(path).exists()
132    }
133}
134
135#[must_use]
136pub fn get_cloud_paths() -> CloudPaths {
137    let project_ctx = ProjectContext::discover();
138    CloudPaths::from_project_context(&project_ctx)
139}