systemprompt_generator/build/
orchestrator.rs1use indicatif::{ProgressBar, ProgressStyle};
8use std::path::PathBuf;
9use std::time::Instant;
10use thiserror::Error;
11
12use super::steps::organize_css;
13use super::validation::validate_build;
14
15pub(super) type Result<T> = std::result::Result<T, BuildError>;
16
17#[derive(Error, Debug)]
18pub enum BuildError {
19 #[error("CSS organization failed: {0}")]
20 CssOrganizationFailed(String),
21
22 #[error("Validation failed: {0}")]
23 ValidationFailed(String),
24
25 #[error("I/O error: {0}")]
26 Io(#[from] std::io::Error),
27
28 #[error("Process execution error: {message}")]
29 ProcessError { message: String },
30
31 #[error("Configuration error: {message}")]
32 ConfigError { message: String },
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum BuildMode {
37 Development,
38 Production,
39 Docker,
40}
41
42impl BuildMode {
43 #[must_use]
44 pub fn parse(s: &str) -> Option<Self> {
45 match s.to_lowercase().as_str() {
46 "development" | "dev" => Some(Self::Development),
47 "production" | "prod" => Some(Self::Production),
48 "docker" => Some(Self::Docker),
49 _ => None,
50 }
51 }
52
53 #[must_use]
54 pub const fn as_str(&self) -> &'static str {
55 match self {
56 Self::Development => "development",
57 Self::Production => "production",
58 Self::Docker => "docker",
59 }
60 }
61}
62
63#[derive(Debug)]
64pub struct BuildOrchestrator {
65 web_dir: PathBuf,
66 mode: BuildMode,
67}
68
69impl BuildOrchestrator {
70 #[must_use]
71 pub const fn new(web_dir: PathBuf, mode: BuildMode) -> Self {
72 Self { web_dir, mode }
73 }
74
75 #[must_use]
76 pub const fn mode(&self) -> BuildMode {
77 self.mode
78 }
79
80 pub async fn build(&self) -> Result<()> {
81 let start = Instant::now();
82 let pb = create_progress_bar();
83 self.execute_build_steps(&pb).await?;
84 finish_build(&pb, start);
85 Ok(())
86 }
87
88 async fn execute_build_steps(&self, pb: &ProgressBar) -> Result<()> {
89 pb.set_message("CSS Organization");
90 organize_css(&self.web_dir).await?;
91 pb.inc(1);
92
93 pb.set_message("Validation");
94 validate_build(&self.web_dir).await?;
95 pb.inc(1);
96
97 Ok(())
98 }
99
100 pub async fn validate_only(&self) -> Result<()> {
101 tracing::info!("Validating build");
102 validate_build(&self.web_dir).await
103 }
104}
105
106fn create_progress_bar() -> ProgressBar {
107 let pb = ProgressBar::new(2);
108 pb.set_style(
109 ProgressStyle::default_bar()
110 .template("{msg} [{bar:40.cyan/blue}] {pos}/{len}")
111 .unwrap_or_else(|_| ProgressStyle::default_bar())
112 .progress_chars("=>-"),
113 );
114 pb
115}
116
117fn finish_build(pb: &ProgressBar, start: Instant) {
118 pb.finish_with_message("Build complete");
119 tracing::info!(
120 duration_secs = start.elapsed().as_secs_f64(),
121 "Build successful"
122 );
123}