From 4de1d0ddd589be3bfe2693c6102f9b5464acb8b0 Mon Sep 17 00:00:00 2001 From: diogo464 Date: Thu, 19 Jun 2025 09:04:27 +0100 Subject: Switch to anyhow for improved error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace Box with anyhow::Result throughout - Add comprehensive assert_cmd documentation to CLAUDE.md - Create detailed improvement plan in IMPROVEMENT_PLAN.md - Use anyhow::anyhow\! for custom error messages - Add Context trait for better error context where applicable This provides better error messages and more idiomatic Rust error handling. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/main.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index e0545e6..12a08b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use std::path::Path; use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; use std::sync::mpsc::channel; use glob::glob; +use anyhow::{Result, Context}; #[derive(Parser)] #[command(name = "demon")] @@ -114,11 +115,11 @@ fn main() { } } -fn run_command(command: Commands) -> Result<(), Box> { +fn run_command(command: Commands) -> Result<()> { match command { Commands::Run(args) => { if args.command.is_empty() { - return Err("Command cannot be empty".into()); + return Err(anyhow::anyhow!("Command cannot be empty")); } run_daemon(&args.id, &args.command) } @@ -147,14 +148,14 @@ fn run_command(command: Commands) -> Result<(), Box> { } } -fn run_daemon(id: &str, command: &[String]) -> Result<(), Box> { +fn run_daemon(id: &str, command: &[String]) -> Result<()> { let pid_file = format!("{}.pid", id); let stdout_file = format!("{}.stdout", id); let stderr_file = format!("{}.stderr", id); // Check if process is already running if is_process_running(&pid_file)? { - return Err(format!("Process '{}' is already running", id).into()); + return Err(anyhow::anyhow!("Process '{}' is already running", id)); } tracing::info!("Starting daemon '{}' with command: {:?}", id, command); @@ -177,7 +178,7 @@ fn run_daemon(id: &str, command: &[String]) -> Result<(), Box Result<(), Box Result> { +fn is_process_running(pid_file: &str) -> Result { // Try to read the PID file let mut file = match File::open(pid_file) { Ok(f) => f, @@ -214,7 +215,7 @@ fn is_process_running(pid_file: &str) -> Result Ok(output.status.success()) } -fn stop_daemon(id: &str, timeout: u64) -> Result<(), Box> { +fn stop_daemon(id: &str, timeout: u64) -> Result<()> { let pid_file = format!("{}.pid", id); // Check if PID file exists @@ -255,7 +256,7 @@ fn stop_daemon(id: &str, timeout: u64) -> Result<(), Box> .output()?; if !output.status.success() { - return Err(format!("Failed to send SIGTERM to PID {}", pid).into()); + return Err(anyhow::anyhow!("Failed to send SIGTERM to PID {}", pid)); } // Wait for the process to terminate @@ -280,14 +281,14 @@ fn stop_daemon(id: &str, timeout: u64) -> Result<(), Box> .output()?; if !output.status.success() { - return Err(format!("Failed to send SIGKILL to PID {}", pid).into()); + return Err(anyhow::anyhow!("Failed to send SIGKILL to PID {}", pid)); } // Wait a bit more for SIGKILL to take effect thread::sleep(Duration::from_secs(1)); if is_process_running_by_pid(pid) { - return Err(format!("Process {} is still running after SIGKILL", pid).into()); + return Err(anyhow::anyhow!("Process {} is still running after SIGKILL", pid)); } println!("Process '{}' (PID: {}) terminated forcefully", id, pid); @@ -307,7 +308,7 @@ fn is_process_running_by_pid(pid: u32) -> bool { } } -fn cat_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<(), Box> { +fn cat_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<()> { let stdout_file = format!("{}.stdout", id); let stderr_file = format!("{}.stderr", id); @@ -348,7 +349,7 @@ fn cat_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<(), Box Result<(), Box> { +fn tail_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<()> { let stdout_file = format!("{}.stdout", id); let stderr_file = format!("{}.stderr", id); @@ -464,7 +465,7 @@ fn tail_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<(), Box Result> { +fn read_file_content(file: &mut File) -> Result { let mut content = String::new(); file.read_to_string(&mut content)?; Ok(content) @@ -474,7 +475,7 @@ fn handle_file_change( file_path: &str, positions: &mut std::collections::HashMap, show_headers: bool -) -> Result<(), Box> { +) -> Result<()> { let mut file = File::open(file_path)?; let current_pos = positions.get(file_path).copied().unwrap_or(0); @@ -500,7 +501,7 @@ fn handle_file_change( Ok(()) } -fn list_daemons() -> Result<(), Box> { +fn list_daemons() -> Result<()> { println!("{:<20} {:<8} {:<10} {}", "ID", "PID", "STATUS", "COMMAND"); println!("{}", "-".repeat(50)); @@ -557,7 +558,7 @@ fn list_daemons() -> Result<(), Box> { Ok(()) } -fn status_daemon(id: &str) -> Result<(), Box> { +fn status_daemon(id: &str) -> Result<()> { let pid_file = format!("{}.pid", id); let stdout_file = format!("{}.stdout", id); let stderr_file = format!("{}.stderr", id); @@ -614,7 +615,7 @@ fn status_daemon(id: &str) -> Result<(), Box> { Ok(()) } -fn clean_orphaned_files() -> Result<(), Box> { +fn clean_orphaned_files() -> Result<()> { tracing::info!("Scanning for orphaned daemon files..."); let mut cleaned_count = 0; -- cgit