dampen_cli/commands/
run.rs1#![allow(clippy::print_stderr, clippy::print_stdout)]
2
3use std::path::Path;
9use std::process::Command;
10
11#[derive(clap::Args)]
13pub struct RunArgs {
14 #[arg(short, long)]
16 package: Option<String>,
17
18 #[arg(last = true)]
20 app_args: Vec<String>,
21
22 #[arg(short, long)]
24 verbose: bool,
25
26 #[arg(long)]
28 release: bool,
29
30 #[arg(long, value_delimiter = ',')]
32 features: Vec<String>,
33}
34
35pub fn execute(args: &RunArgs) -> Result<(), String> {
65 if !Path::new("Cargo.toml").exists() {
67 return Err("Cargo.toml not found. Are you in a Rust project directory?".to_string());
68 }
69
70 let mode = if args.release {
71 "codegen"
72 } else {
73 "interpreted"
74 };
75
76 if args.verbose {
77 eprintln!("Running in {} mode...", mode);
78 eprintln!(
79 "Profile: {}",
80 if args.release { "release" } else { "debug" }
81 );
82 }
83
84 if args.release {
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 !build_rs_exists {
95 return Err(
96 "build.rs not found. Codegen mode requires build.rs for code generation.\n\
97 Tip: Use 'dampen run' (without --release) for interpreted mode,\n\
98 or ensure you're in the correct project directory."
99 .to_string(),
100 );
101 }
102
103 let mut build_cmd = Command::new("cargo");
105 build_cmd.arg("build");
106
107 if let Some(ref package) = args.package {
108 build_cmd.arg("-p").arg(package);
109 }
110
111 if args.verbose {
112 build_cmd.arg("--verbose");
113 }
114
115 build_cmd.arg("--release");
117 build_cmd.arg("--no-default-features");
118
119 let mut features = vec!["codegen".to_string()];
120 features.extend(args.features.clone());
121
122 build_cmd.arg("--features").arg(features.join(","));
123
124 if args.verbose {
125 let features_str = features.join(",");
126 eprintln!(
127 "Building: cargo build --release --no-default-features --features {}",
128 features_str
129 );
130 }
131
132 let build_status = build_cmd
133 .status()
134 .map_err(|e| format!("Failed to execute cargo build: {}", e))?;
135
136 if !build_status.success() {
137 return Err("Build failed".to_string());
138 }
139
140 if args.verbose {
141 eprintln!("Build successful! Now running application...");
142 }
143
144 let mut run_cmd = Command::new("cargo");
146 run_cmd.arg("run");
147
148 if let Some(ref package) = args.package {
149 run_cmd.arg("-p").arg(package);
150 }
151
152 if args.verbose {
153 run_cmd.arg("--verbose");
154 }
155
156 run_cmd.arg("--release");
158
159 if !args.app_args.is_empty() {
161 run_cmd.arg("--");
162 run_cmd.args(&args.app_args);
163 }
164
165 if args.verbose {
166 eprintln!("Running: cargo run --release");
167 if !args.app_args.is_empty() {
168 eprintln!("Application args: {:?}", args.app_args);
169 }
170 }
171
172 let run_status = run_cmd
173 .status()
174 .map_err(|e| format!("Failed to execute cargo run: {}", e))?;
175
176 if !run_status.success() {
177 return Err("Run command failed".to_string());
178 }
179
180 Ok(())
181 } else {
182 let mut cmd = Command::new("cargo");
184 cmd.arg("run");
185
186 if let Some(ref package) = args.package {
187 cmd.arg("-p").arg(package);
188 }
189
190 if args.verbose {
191 cmd.arg("--verbose");
192 }
193
194 let mut features = vec!["interpreted".to_string()];
196 features.extend(args.features.clone());
197
198 cmd.arg("--features").arg(features.join(","));
199
200 if !args.app_args.is_empty() {
202 cmd.arg("--");
203 cmd.args(&args.app_args);
204 }
205
206 if args.verbose {
208 let features_str = features.join(",");
209 eprintln!("Executing: cargo run --features {}", features_str);
210 if !args.app_args.is_empty() {
211 eprintln!("Application args: {:?}", args.app_args);
212 }
213 }
214
215 let status = cmd
216 .status()
217 .map_err(|e| format!("Failed to execute cargo: {}", e))?;
218
219 if !status.success() {
220 return Err("Run command failed".to_string());
221 }
222
223 Ok(())
224 }
225}