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