systemprompt_loader/
profile_loader.rs1use anyhow::{Context, Result};
2use std::path::Path;
3use systemprompt_config::load_profile_with_catalog;
4use systemprompt_models::Profile;
5
6#[derive(Debug, Clone, Copy)]
7pub struct ProfileLoader;
8
9impl ProfileLoader {
10 pub fn load_from_path(profile_path: &Path) -> Result<Profile> {
11 load_profile_with_catalog(profile_path)
12 .with_context(|| format!("Failed to read profile: {}", profile_path.display()))
13 }
14
15 pub fn load(services_path: &Path, profile_name: &str) -> Result<Profile> {
16 let profile_path = services_path
17 .join("profiles")
18 .join(format!("{profile_name}.secrets.profile.yaml"));
19
20 Self::load_from_path(&profile_path)
21 }
22
23 pub fn load_from_path_and_validate(profile_path: &Path) -> Result<Profile> {
24 let profile = Self::load_from_path(profile_path)?;
25 profile.validate()?;
26 Ok(profile)
27 }
28
29 pub fn load_and_validate(services_path: &Path, profile_name: &str) -> Result<Profile> {
30 let profile = Self::load(services_path, profile_name)?;
31 profile.validate()?;
32 Ok(profile)
33 }
34
35 pub fn save(profile: &Profile, services_path: &Path) -> Result<()> {
36 let profiles_dir = services_path.join("profiles");
37 std::fs::create_dir_all(&profiles_dir).context("Failed to create profiles directory")?;
38
39 let profile_path = profiles_dir.join(format!("{}.secrets.profile.yaml", profile.name));
40 let content = profile.to_yaml()?;
41
42 let content_with_header = format!(
43 "# systemprompt.io Profile: {}\n# \n# WARNING: This file contains secrets.\n# DO NOT \
44 commit to version control.\n\n{content}",
45 profile.display_name
46 );
47
48 std::fs::write(&profile_path, content_with_header)
49 .with_context(|| format!("Failed to write profile: {}", profile_path.display()))
50 }
51
52 pub fn list_available(services_path: &Path) -> Vec<String> {
53 let profiles_dir = services_path.join("profiles");
54
55 if !profiles_dir.exists() {
56 return Vec::new();
57 }
58
59 match std::fs::read_dir(&profiles_dir) {
60 Ok(entries) => entries
61 .filter_map(std::result::Result::ok)
62 .filter_map(|e| {
63 let name = e.file_name().to_string_lossy().to_string();
64 name.strip_suffix(".secrets.profile.yaml")
65 .map(ToString::to_string)
66 })
67 .collect(),
68 Err(e) => {
69 tracing::warn!(
70 error = %e,
71 path = %profiles_dir.display(),
72 "Failed to read profiles directory"
73 );
74 Vec::new()
75 },
76 }
77 }
78}