Skip to main content

systemprompt_generator/build/
orchestrator.rs

1use 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}