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