systemprompt_models/bootstrap/
mod.rs1use std::marker::PhantomData;
9use std::path::Path;
10
11use anyhow::{Context, Result};
12
13use crate::profile_bootstrap::ProfileBootstrap;
14use crate::secrets_bootstrap::SecretsBootstrap;
15use crate::{AppPaths, Config, PathsConfig};
16
17pub trait BootstrapState {}
18
19#[derive(Debug, Clone, Copy)]
20pub struct Uninitialized;
21impl BootstrapState for Uninitialized {}
22
23#[derive(Debug, Clone, Copy)]
24pub struct ProfileInitialized;
25impl BootstrapState for ProfileInitialized {}
26
27#[derive(Debug, Clone, Copy)]
28pub struct SecretsInitialized;
29impl BootstrapState for SecretsInitialized {}
30
31#[derive(Debug, Clone, Copy)]
32pub struct PathsInitialized;
33impl BootstrapState for PathsInitialized {}
34
35#[derive(Debug)]
36pub struct BootstrapSequence<S: BootstrapState> {
37 _state: PhantomData<S>,
38}
39
40impl Default for BootstrapSequence<Uninitialized> {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl BootstrapSequence<Uninitialized> {
47 #[must_use]
48 pub const fn new() -> Self {
49 Self {
50 _state: PhantomData,
51 }
52 }
53
54 pub fn with_profile(self, path: &Path) -> Result<BootstrapSequence<ProfileInitialized>> {
55 let Self { _state: _ } = self;
56 ProfileBootstrap::init_from_path(path)
57 .with_context(|| format!("Profile initialization failed from: {}", path.display()))?;
58
59 Ok(BootstrapSequence {
60 _state: PhantomData,
61 })
62 }
63
64 #[must_use]
65 pub const fn skip_profile(self) -> Self {
66 self
67 }
68}
69
70impl BootstrapSequence<ProfileInitialized> {
71 pub fn with_secrets(self) -> Result<BootstrapSequence<SecretsInitialized>> {
72 let Self { _state: _ } = self;
73 SecretsBootstrap::init().context("Secrets initialization failed")?;
74
75 Ok(BootstrapSequence {
76 _state: PhantomData,
77 })
78 }
79
80 #[must_use]
81 pub const fn skip_secrets(self) -> Self {
82 self
83 }
84}
85
86impl BootstrapSequence<SecretsInitialized> {
87 pub fn with_paths(self) -> Result<BootstrapSequence<PathsInitialized>> {
88 let Self { _state: _ } = self;
89 let profile = ProfileBootstrap::get()?;
90 AppPaths::init(&profile.paths).context("Failed to initialize paths")?;
91 Config::try_init().context("Failed to initialize configuration")?;
92
93 Ok(BootstrapSequence {
94 _state: PhantomData,
95 })
96 }
97
98 pub fn with_paths_config(
99 self,
100 paths_config: &PathsConfig,
101 ) -> Result<BootstrapSequence<PathsInitialized>> {
102 let Self { _state: _ } = self;
103 AppPaths::init(paths_config).context("Failed to initialize paths")?;
104 Config::try_init().context("Failed to initialize configuration")?;
105
106 Ok(BootstrapSequence {
107 _state: PhantomData,
108 })
109 }
110
111 #[must_use]
112 pub const fn skip_paths(self) -> Self {
113 self
114 }
115}
116
117impl BootstrapSequence<PathsInitialized> {
118 #[must_use]
119 pub const fn complete(self) -> BootstrapComplete {
120 let Self { _state: _ } = self;
121 BootstrapComplete { _private: () }
122 }
123}
124
125#[derive(Debug, Clone, Copy)]
126pub struct BootstrapComplete {
127 _private: (),
128}
129
130pub mod presets {
131 use std::path::Path;
132
133 use anyhow::Result;
134
135 use super::{
136 BootstrapComplete, BootstrapSequence, ProfileInitialized, SecretsInitialized, Uninitialized,
137 };
138
139 pub fn full(profile_path: &Path) -> Result<BootstrapComplete> {
140 Ok(BootstrapSequence::<Uninitialized>::new()
141 .with_profile(profile_path)?
142 .with_secrets()?
143 .with_paths()?
144 .complete())
145 }
146
147 pub fn profile_and_secrets(
148 profile_path: &Path,
149 ) -> Result<BootstrapSequence<SecretsInitialized>> {
150 BootstrapSequence::<Uninitialized>::new()
151 .with_profile(profile_path)?
152 .with_secrets()
153 }
154
155 pub fn profile_only(profile_path: &Path) -> Result<BootstrapSequence<ProfileInitialized>> {
156 BootstrapSequence::<Uninitialized>::new().with_profile(profile_path)
157 }
158}