dampen_cli/commands/
build.rs

1#![allow(clippy::print_stderr, clippy::print_stdout)]
2
3//! Build command - generates production Rust code from Dampen UI files
4
5use std::path::Path;
6
7/// Build command arguments
8#[derive(clap::Args)]
9pub struct BuildArgs {
10    /// Input directory containing .dampen files (default: ui/)
11    #[arg(short, long, default_value = "ui")]
12    input: String,
13
14    /// Output file for generated code (default: src/ui_generated.rs)
15    #[arg(short, long, default_value = "src/ui_generated.rs")]
16    output: String,
17
18    /// Model struct name (default: Model)
19    #[arg(long, default_value = "Model")]
20    model: String,
21
22    /// Message enum name (default: Message)
23    #[arg(long, default_value = "Message")]
24    message: String,
25
26    /// Verbose output
27    #[arg(short, long)]
28    verbose: bool,
29
30    /// Package to build (if workspace has multiple packages)
31    #[arg(short, long)]
32    package: Option<String>,
33
34    /// Additional features to enable (beyond codegen)
35    #[arg(long, value_delimiter = ',')]
36    features: Vec<String>,
37}
38
39/// Execute the build command
40///
41/// Builds the application in debug mode with codegen.
42///
43/// # Mode Behavior
44///
45/// - **Debug Mode with Codegen**: Compile-time code generation without optimizations
46/// - Faster compilation than release mode
47/// - Useful for debugging production codegen behavior
48/// - Use `dampen release` for optimized production builds
49///
50/// # Examples
51///
52/// ```bash
53/// # Basic debug build with codegen
54/// dampen build
55///
56/// # Build specific package in workspace
57/// dampen build -p my-app
58///
59/// # Enable additional features
60/// dampen build --features tokio,logging
61/// ```
62pub fn execute(args: &BuildArgs) -> Result<(), String> {
63    // Run debug build with codegen
64    execute_production_build(args)
65}
66
67/// Execute production build using cargo build
68fn execute_production_build(args: &BuildArgs) -> Result<(), String> {
69    use std::process::Command;
70
71    if args.verbose {
72        eprintln!("Running debug build with codegen...");
73    }
74
75    // Check if build.rs exists
76    if !Path::new("build.rs").exists() {
77        return Err(
78            "build.rs not found. This project may not be configured for codegen builds."
79                .to_string(),
80        );
81    }
82
83    // Check if Cargo.toml exists
84    if !Path::new("Cargo.toml").exists() {
85        return Err("Cargo.toml not found. Are you in a Rust project directory?".to_string());
86    }
87
88    // Build the cargo command
89    let mut cmd = Command::new("cargo");
90    cmd.arg("build");
91
92    // Add package specification if provided
93    if let Some(ref package) = args.package {
94        cmd.arg("-p").arg(package);
95    }
96
97    if args.verbose {
98        cmd.arg("--verbose");
99    }
100
101    // Build features list: always include 'codegen', plus any user-specified features
102    let mut all_features = vec!["codegen".to_string()];
103    all_features.extend(args.features.clone());
104
105    // Add features flag
106    cmd.arg("--features").arg(all_features.join(","));
107
108    // Execute cargo build
109    if args.verbose {
110        let features_str = all_features.join(",");
111        eprintln!("Executing: cargo build --features {}", features_str);
112    }
113
114    let status = cmd
115        .status()
116        .map_err(|e| format!("Failed to execute cargo: {}", e))?;
117
118    if !status.success() {
119        return Err("Build failed".to_string());
120    }
121
122    if args.verbose {
123        eprintln!("Build successful! Binary is in target/debug/");
124    }
125
126    eprintln!("Debug build completed successfully!");
127    eprintln!("Use 'dampen release' for optimized production builds.");
128    Ok(())
129}