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