dampen_cli/commands/
build.rs1#![allow(clippy::print_stderr, clippy::print_stdout)]
2
3use std::path::Path;
6
7#[derive(clap::Args)]
9pub struct BuildArgs {
10 #[arg(short, long, default_value = "ui")]
12 input: String,
13
14 #[arg(short, long, default_value = "src/ui_generated.rs")]
16 output: String,
17
18 #[arg(long, default_value = "Model")]
20 model: String,
21
22 #[arg(long, default_value = "Message")]
24 message: String,
25
26 #[arg(short, long)]
28 verbose: bool,
29
30 #[arg(short, long)]
32 package: Option<String>,
33
34 #[arg(long, value_delimiter = ',')]
36 features: Vec<String>,
37
38 #[arg(long)]
40 release: bool,
41}
42
43pub fn execute(args: &BuildArgs) -> Result<(), String> {
70 execute_production_build(args)
71}
72
73fn execute_production_build(args: &BuildArgs) -> Result<(), String> {
74 use std::process::Command;
75
76 let mode = if args.release {
77 "codegen"
78 } else {
79 "interpreted"
80 };
81
82 if args.verbose {
83 eprintln!("Running {} build...", mode);
84 }
85
86 let build_rs_exists = Path::new("build.rs").exists()
89 || args
90 .package
91 .as_ref()
92 .is_some_and(|pkg| Path::new("examples").join(pkg).join("build.rs").exists());
93
94 if args.release && !build_rs_exists {
95 return Err(
96 "build.rs not found. Codegen mode requires build.rs for code generation.\n\
97 Tip: Use 'dampen build' (without --release) for interpreted mode,\n\
98 or ensure you're in the correct project directory."
99 .to_string(),
100 );
101 }
102
103 if !Path::new("Cargo.toml").exists() {
104 return Err("Cargo.toml not found. Are you in a Rust project directory?".to_string());
105 }
106
107 let mut cmd = Command::new("cargo");
108 cmd.arg("build");
109
110 if let Some(ref package) = args.package {
111 cmd.arg("-p").arg(package);
112 }
113
114 if args.verbose {
115 cmd.arg("--verbose");
116 }
117
118 let all_features = if args.release {
120 cmd.arg("--release");
122 cmd.arg("--no-default-features");
123 let mut features = vec!["codegen".to_string()];
124 features.extend(args.features.clone());
125 features
126 } else {
127 let mut features = vec!["interpreted".to_string()];
129 features.extend(args.features.clone());
130 features
131 };
132
133 cmd.arg("--features").arg(all_features.join(","));
134
135 if args.verbose {
136 let features_str = all_features.join(",");
137 let cargo_cmd = if args.release {
138 format!(
139 "cargo build --release --no-default-features --features {}",
140 features_str
141 )
142 } else {
143 format!("cargo build --features {}", features_str)
144 };
145 eprintln!("Executing: {}", cargo_cmd);
146 }
147
148 let status = cmd
149 .status()
150 .map_err(|e| format!("Failed to execute cargo: {}", e))?;
151
152 if !status.success() {
153 return Err("Build failed".to_string());
154 }
155
156 if args.verbose {
157 let output_dir = if args.release {
158 "target/release/"
159 } else {
160 "target/debug/"
161 };
162 eprintln!("Build successful! Binary is in {}", output_dir);
163 }
164
165 if args.release {
166 eprintln!("Release build (codegen) completed successfully!");
167 } else {
168 eprintln!("Debug build (interpreted) completed successfully!");
169 eprintln!(
170 "Use 'dampen build --release' or 'dampen release' for optimized production builds."
171 );
172 }
173
174 Ok(())
175}
176
177pub fn execute_release_build(
180 package: Option<String>,
181 features: Vec<String>,
182 verbose: bool,
183 target_dir: Option<String>,
184) -> Result<(), String> {
185 use std::process::Command;
186
187 let mode = "codegen";
188
189 if verbose {
190 eprintln!("Running {} build...", mode);
191 }
192
193 let build_rs_exists = Path::new("build.rs").exists()
196 || package
197 .as_ref()
198 .is_some_and(|pkg| Path::new("examples").join(pkg).join("build.rs").exists());
199
200 if !build_rs_exists {
201 return Err(
202 "build.rs not found. Codegen mode requires build.rs for code generation.\n\
203 Tip: Use 'dampen build' (without --release) for interpreted mode,\n\
204 or ensure you're in the correct project directory."
205 .to_string(),
206 );
207 }
208
209 if !Path::new("Cargo.toml").exists() {
210 return Err("Cargo.toml not found. Are you in a Rust project directory?".to_string());
211 }
212
213 let mut cmd = Command::new("cargo");
214 cmd.arg("build");
215 cmd.arg("--release");
216
217 if let Some(ref pkg) = package {
218 cmd.arg("-p").arg(pkg);
219 }
220
221 if let Some(ref dir) = target_dir {
222 cmd.arg("--target-dir").arg(dir);
223 }
224
225 if verbose {
226 cmd.arg("--verbose");
227 }
228
229 cmd.arg("--no-default-features");
231 let mut all_features = vec!["codegen".to_string()];
232 all_features.extend(features);
233 cmd.arg("--features").arg(all_features.join(","));
234
235 if verbose {
236 let features_str = all_features.join(",");
237 eprintln!(
238 "Executing: cargo build --release --no-default-features --features {}",
239 features_str
240 );
241 }
242
243 let status = cmd
244 .status()
245 .map_err(|e| format!("Failed to execute cargo: {}", e))?;
246
247 if !status.success() {
248 return Err("Build failed".to_string());
249 }
250
251 if verbose {
252 eprintln!("Build successful! Binary is in target/release/");
253 }
254
255 eprintln!("Release build (codegen) completed successfully!");
256
257 Ok(())
258}