···4646 /// Returns true if recompilation is needed, false if we can just rerun the binary
4747 pub async fn needs_recompile(&self, changed_paths: &[PathBuf]) -> bool {
4848 let dep_tracker = self.dep_tracker.read().await;
4949-5050- if let Some(tracker) = dep_tracker.as_ref() {
5151- if tracker.has_dependencies() {
5252- let needs_recompile = tracker.needs_recompile(changed_paths);
5353- if !needs_recompile {
5454- debug!(name: "build", "Changed files are not dependencies, rerun binary without recompile");
5555- }
5656- return needs_recompile;
4949+5050+ if let Some(tracker) = dep_tracker.as_ref()
5151+ && tracker.has_dependencies()
5252+ {
5353+ let needs_recompile = tracker.needs_recompile(changed_paths);
5454+ if !needs_recompile {
5555+ debug!(name: "build", "Changed files are not dependencies, rerun binary without recompile");
5756 }
5757+ return needs_recompile;
5858 }
5959-5959+6060 // If we don't have a dependency tracker yet, always recompile
6161 true
6262 }
···6464 /// Rerun the binary without recompiling
6565 pub async fn rerun_binary(&self) -> Result<bool, Box<dyn std::error::Error>> {
6666 let binary_path = self.binary_path.read().await;
6767-6767+6868 let Some(path) = binary_path.as_ref() else {
6969 warn!(name: "build", "No binary path available, falling back to full rebuild");
7070 return self.start_build().await;
···7676 }
77777878 info!(name: "build", "Rerunning binary without recompilation...");
7979-7979+8080 // Notify that build is starting (even though we're just rerunning)
8181 update_status(
8282 &self.websocket_tx,
···8787 .await;
88888989 let build_start_time = Instant::now();
9090-9090+9191 let child = Command::new(path)
9292- .envs([
9393- ("MAUDIT_DEV", "true"),
9494- ("MAUDIT_QUIET", "true"),
9595- ])
9292+ .envs([("MAUDIT_DEV", "true"), ("MAUDIT_QUIET", "true")])
9693 .stdout(std::process::Stdio::piped())
9794 .stderr(std::process::Stdio::piped())
9895 .spawn()?;
999610097 // Wait for the process to complete
10198 let output = child.wait_with_output().await?;
102102-9999+103100 let duration = build_start_time.elapsed();
104104- let formatted_elapsed_time = format_elapsed_time(
105105- duration,
106106- &FormatElapsedTimeOptions::default_dev(),
107107- );
101101+ let formatted_elapsed_time =
102102+ format_elapsed_time(duration, &FormatElapsedTimeOptions::default_dev());
108103109104 if output.status.success() {
110105 info!(name: "build", "Binary rerun finished {}", formatted_elapsed_time);
···119114 } else {
120115 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
121116 let stdout = String::from_utf8_lossy(&output.stdout).to_string();
122122- error!(name: "build", "Binary rerun failed {}\nstdout: {}\nstderr: {}",
117117+ error!(name: "build", "Binary rerun failed {}\nstdout: {}\nstderr: {}",
123118 formatted_elapsed_time, stdout, stderr);
124119 update_status(
125120 &self.websocket_tx,
···282277 let build_type = if is_initial { "Initial build" } else { "Rebuild" };
283278 info!(name: "build", "{} finished {}", build_type, formatted_elapsed_time);
284279 update_status(&websocket_tx, current_status.clone(), StatusType::Success, "Build finished successfully").await;
285285-280280+286281 // Update dependency tracker after successful build
287282 Self::update_dependency_tracker_after_build(dep_tracker_clone.clone(), binary_path_clone.clone()).await;
288288-283283+289284 true
290285 } else {
291286 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
···380375 .and_then(|n| n.as_str())
381376 {
382377 // Check if there's a [[bin]] section with a different name
383383- if let Some(bins) = cargo_toml.get("bin").and_then(|b| b.as_array()) {
384384- if let Some(first_bin) = bins.first() {
385385- if let Some(bin_name) = first_bin.get("name").and_then(|n| n.as_str()) {
386386- return Ok(bin_name.to_string());
387387- }
388388- }
378378+ if let Some(bins) = cargo_toml.get("bin").and_then(|b| b.as_array())
379379+ && let Some(first_bin) = bins.first()
380380+ && let Some(bin_name) = first_bin.get("name").and_then(|n| n.as_str())
381381+ {
382382+ return Ok(bin_name.to_string());
389383 }
390390-384384+391385 // No explicit bin name, use package name
392386 return Ok(package_name.to_string());
393387 }
+5-8
crates/maudit-cli/src/dev/dep_tracker.rs
···5555 let mut current = std::env::current_dir()?;
5656 loop {
5757 let cargo_toml = current.join("Cargo.toml");
5858- if cargo_toml.exists() {
5959- if let Ok(content) = fs::read_to_string(&cargo_toml) {
6060- if content.contains("[workspace]") {
5858+ if cargo_toml.exists()
5959+ && let Ok(content) = fs::read_to_string(&cargo_toml)
6060+ && content.contains("[workspace]") {
6161 let workspace_target = current.join("target").join("debug");
6262 if workspace_target.exists() {
6363 debug!("Using workspace target directory: {:?}", workspace_target);
6464 return Ok(workspace_target);
6565 }
6666 }
6767- }
6868- }
69677068 // Move up to parent directory
7169 if !current.pop() {
···181179 if matches {
182180 // Check if the file was modified after we last tracked it
183181 if let Ok(metadata) = fs::metadata(changed_path) {
184184- if let Ok(current_modified) = metadata.modified() {
185185- if current_modified > *last_modified {
182182+ if let Ok(current_modified) = metadata.modified()
183183+ && current_modified > *last_modified {
186184 debug!(
187185 "Dependency {:?} was modified, recompile needed",
188186 changed_path
189187 );
190188 return true;
191189 }
192192- }
193190 } else {
194191 // File was deleted or can't be read, assume recompile is needed
195192 debug!(