diff options
| author | diogo464 <[email protected]> | 2025-06-23 10:36:24 +0100 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2025-06-23 10:36:24 +0100 |
| commit | b257b2259dc3ad7d0aa4df86ef241b66932204a9 (patch) | |
| tree | 1228b0cf002d102cd5e81db7c7321386e188fdf3 | |
| parent | 4e9134b98866364f0eb35cd693da185ec389a3db (diff) | |
Add pre-commit hook for cargo fmt and apply formatting
- Created pre-commit hook that runs cargo fmt --check
- If formatting issues found, runs cargo fmt and asks for re-commit
- Applied cargo fmt to fix existing formatting issues
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
| -rw-r--r-- | src/main.rs | 73 | ||||
| -rw-r--r-- | tests/cli.rs | 78 |
2 files changed, 105 insertions, 46 deletions
diff --git a/src/main.rs b/src/main.rs index dd7793f..22c2937 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -293,7 +293,14 @@ fn run_command(command: Commands) -> Result<()> { | |||
| 293 | let show_stdout = !args.stderr || args.stdout; | 293 | let show_stdout = !args.stderr || args.stdout; |
| 294 | let show_stderr = !args.stdout || args.stderr; | 294 | let show_stderr = !args.stdout || args.stderr; |
| 295 | let root_dir = resolve_root_dir(&args.global)?; | 295 | let root_dir = resolve_root_dir(&args.global)?; |
| 296 | tail_logs(&args.id, show_stdout, show_stderr, args.follow, args.lines, &root_dir) | 296 | tail_logs( |
| 297 | &args.id, | ||
| 298 | show_stdout, | ||
| 299 | show_stderr, | ||
| 300 | args.follow, | ||
| 301 | args.lines, | ||
| 302 | &root_dir, | ||
| 303 | ) | ||
| 297 | } | 304 | } |
| 298 | Commands::Cat(args) => { | 305 | Commands::Cat(args) => { |
| 299 | let show_stdout = !args.stderr || args.stdout; | 306 | let show_stdout = !args.stderr || args.stdout; |
| @@ -326,25 +333,27 @@ fn run_command(command: Commands) -> Result<()> { | |||
| 326 | 333 | ||
| 327 | fn find_git_root() -> Result<PathBuf> { | 334 | fn find_git_root() -> Result<PathBuf> { |
| 328 | let mut current = std::env::current_dir()?; | 335 | let mut current = std::env::current_dir()?; |
| 329 | 336 | ||
| 330 | // Find the git root directory | 337 | // Find the git root directory |
| 331 | let git_root = loop { | 338 | let git_root = loop { |
| 332 | let git_path = current.join(".git"); | 339 | let git_path = current.join(".git"); |
| 333 | if git_path.exists() { | 340 | if git_path.exists() { |
| 334 | break current; | 341 | break current; |
| 335 | } | 342 | } |
| 336 | 343 | ||
| 337 | match current.parent() { | 344 | match current.parent() { |
| 338 | Some(parent) => current = parent.to_path_buf(), | 345 | Some(parent) => current = parent.to_path_buf(), |
| 339 | None => return Err(anyhow::anyhow!( | 346 | None => { |
| 340 | "No git repository found. Please specify --root-dir or run from within a git repository" | 347 | return Err(anyhow::anyhow!( |
| 341 | )), | 348 | "No git repository found. Please specify --root-dir or run from within a git repository" |
| 349 | )); | ||
| 350 | } | ||
| 342 | } | 351 | } |
| 343 | }; | 352 | }; |
| 344 | 353 | ||
| 345 | // Create .demon subdirectory within git root | 354 | // Create .demon subdirectory within git root |
| 346 | let demon_dir = git_root.join(".demon"); | 355 | let demon_dir = git_root.join(".demon"); |
| 347 | 356 | ||
| 348 | // Handle the case where .demon already exists | 357 | // Handle the case where .demon already exists |
| 349 | if demon_dir.exists() { | 358 | if demon_dir.exists() { |
| 350 | if !demon_dir.is_dir() { | 359 | if !demon_dir.is_dir() { |
| @@ -356,13 +365,13 @@ fn find_git_root() -> Result<PathBuf> { | |||
| 356 | // .demon exists and is a directory, we can use it | 365 | // .demon exists and is a directory, we can use it |
| 357 | return Ok(demon_dir); | 366 | return Ok(demon_dir); |
| 358 | } | 367 | } |
| 359 | 368 | ||
| 360 | // Create .demon directory | 369 | // Create .demon directory |
| 361 | std::fs::create_dir(&demon_dir) | 370 | std::fs::create_dir(&demon_dir) |
| 362 | .with_context(|| format!("Failed to create daemon directory {}", demon_dir.display()))?; | 371 | .with_context(|| format!("Failed to create daemon directory {}", demon_dir.display()))?; |
| 363 | 372 | ||
| 364 | tracing::info!("Created daemon directory: {}", demon_dir.display()); | 373 | tracing::info!("Created daemon directory: {}", demon_dir.display()); |
| 365 | 374 | ||
| 366 | Ok(demon_dir) | 375 | Ok(demon_dir) |
| 367 | } | 376 | } |
| 368 | 377 | ||
| @@ -370,13 +379,19 @@ fn resolve_root_dir(global: &Global) -> Result<PathBuf> { | |||
| 370 | match &global.root_dir { | 379 | match &global.root_dir { |
| 371 | Some(dir) => { | 380 | Some(dir) => { |
| 372 | if !dir.exists() { | 381 | if !dir.exists() { |
| 373 | return Err(anyhow::anyhow!("Specified root directory does not exist: {}", dir.display())); | 382 | return Err(anyhow::anyhow!( |
| 383 | "Specified root directory does not exist: {}", | ||
| 384 | dir.display() | ||
| 385 | )); | ||
| 374 | } | 386 | } |
| 375 | if !dir.is_dir() { | 387 | if !dir.is_dir() { |
| 376 | return Err(anyhow::anyhow!("Specified root path is not a directory: {}", dir.display())); | 388 | return Err(anyhow::anyhow!( |
| 389 | "Specified root path is not a directory: {}", | ||
| 390 | dir.display() | ||
| 391 | )); | ||
| 377 | } | 392 | } |
| 378 | Ok(dir.clone()) | 393 | Ok(dir.clone()) |
| 379 | }, | 394 | } |
| 380 | None => find_git_root(), | 395 | None => find_git_root(), |
| 381 | } | 396 | } |
| 382 | } | 397 | } |
| @@ -428,7 +443,11 @@ fn run_daemon(id: &str, command: &[String], root_dir: &Path) -> Result<()> { | |||
| 428 | // Don't wait for the child - let it run detached | 443 | // Don't wait for the child - let it run detached |
| 429 | std::mem::forget(child); | 444 | std::mem::forget(child); |
| 430 | 445 | ||
| 431 | println!("Started daemon '{}' with PID written to {}", id, pid_file.display()); | 446 | println!( |
| 447 | "Started daemon '{}' with PID written to {}", | ||
| 448 | id, | ||
| 449 | pid_file.display() | ||
| 450 | ); | ||
| 432 | 451 | ||
| 433 | Ok(()) | 452 | Ok(()) |
| 434 | } | 453 | } |
| @@ -820,7 +839,8 @@ fn list_daemons(quiet: bool, root_dir: &Path) -> Result<()> { | |||
| 820 | for entry in find_pid_files(root_dir)? { | 839 | for entry in find_pid_files(root_dir)? { |
| 821 | found_any = true; | 840 | found_any = true; |
| 822 | let path = entry.path(); | 841 | let path = entry.path(); |
| 823 | let filename = path.file_name() | 842 | let filename = path |
| 843 | .file_name() | ||
| 824 | .and_then(|name| name.to_str()) | 844 | .and_then(|name| name.to_str()) |
| 825 | .unwrap_or_default(); | 845 | .unwrap_or_default(); |
| 826 | 846 | ||
| @@ -904,14 +924,22 @@ fn status_daemon(id: &str, root_dir: &Path) -> Result<()> { | |||
| 904 | // Show file information | 924 | // Show file information |
| 905 | if stdout_file.exists() { | 925 | if stdout_file.exists() { |
| 906 | let metadata = std::fs::metadata(&stdout_file)?; | 926 | let metadata = std::fs::metadata(&stdout_file)?; |
| 907 | println!("Stdout file: {} ({} bytes)", stdout_file.display(), metadata.len()); | 927 | println!( |
| 928 | "Stdout file: {} ({} bytes)", | ||
| 929 | stdout_file.display(), | ||
| 930 | metadata.len() | ||
| 931 | ); | ||
| 908 | } else { | 932 | } else { |
| 909 | println!("Stdout file: {} (not found)", stdout_file.display()); | 933 | println!("Stdout file: {} (not found)", stdout_file.display()); |
| 910 | } | 934 | } |
| 911 | 935 | ||
| 912 | if stderr_file.exists() { | 936 | if stderr_file.exists() { |
| 913 | let metadata = std::fs::metadata(&stderr_file)?; | 937 | let metadata = std::fs::metadata(&stderr_file)?; |
| 914 | println!("Stderr file: {} ({} bytes)", stderr_file.display(), metadata.len()); | 938 | println!( |
| 939 | "Stderr file: {} ({} bytes)", | ||
| 940 | stderr_file.display(), | ||
| 941 | metadata.len() | ||
| 942 | ); | ||
| 915 | } else { | 943 | } else { |
| 916 | println!("Stderr file: {} (not found)", stderr_file.display()); | 944 | println!("Stderr file: {} (not found)", stderr_file.display()); |
| 917 | } | 945 | } |
| @@ -942,7 +970,8 @@ fn clean_orphaned_files(root_dir: &Path) -> Result<()> { | |||
| 942 | // Find all .pid files in root directory | 970 | // Find all .pid files in root directory |
| 943 | for entry in find_pid_files(root_dir)? { | 971 | for entry in find_pid_files(root_dir)? { |
| 944 | let path = entry.path(); | 972 | let path = entry.path(); |
| 945 | let filename = path.file_name() | 973 | let filename = path |
| 974 | .file_name() | ||
| 946 | .and_then(|name| name.to_str()) | 975 | .and_then(|name| name.to_str()) |
| 947 | .unwrap_or_default(); | 976 | .unwrap_or_default(); |
| 948 | let id = filename.strip_suffix(".pid").unwrap_or(filename); | 977 | let id = filename.strip_suffix(".pid").unwrap_or(filename); |
| @@ -1000,7 +1029,11 @@ fn clean_orphaned_files(root_dir: &Path) -> Result<()> { | |||
| 1000 | Err(PidFileReadError::FileInvalid(_)) | Err(PidFileReadError::IoError(_)) => { | 1029 | Err(PidFileReadError::FileInvalid(_)) | Err(PidFileReadError::IoError(_)) => { |
| 1001 | println!("Cleaning up invalid PID file: {}", path.display()); | 1030 | println!("Cleaning up invalid PID file: {}", path.display()); |
| 1002 | if let Err(e) = std::fs::remove_file(&path) { | 1031 | if let Err(e) = std::fs::remove_file(&path) { |
| 1003 | tracing::warn!("Failed to remove invalid PID file {}: {}", path.display(), e); | 1032 | tracing::warn!( |
| 1033 | "Failed to remove invalid PID file {}: {}", | ||
| 1034 | path.display(), | ||
| 1035 | e | ||
| 1036 | ); | ||
| 1004 | } else { | 1037 | } else { |
| 1005 | tracing::info!("Removed invalid PID file {}", path.display()); | 1038 | tracing::info!("Removed invalid PID file {}", path.display()); |
| 1006 | cleaned_count += 1; | 1039 | cleaned_count += 1; |
diff --git a/tests/cli.rs b/tests/cli.rs index b97d331..deaa3f0 100644 --- a/tests/cli.rs +++ b/tests/cli.rs | |||
| @@ -36,10 +36,15 @@ fn test_run_missing_command() { | |||
| 36 | let temp_dir = TempDir::new().unwrap(); | 36 | let temp_dir = TempDir::new().unwrap(); |
| 37 | 37 | ||
| 38 | let mut cmd = Command::cargo_bin("demon").unwrap(); | 38 | let mut cmd = Command::cargo_bin("demon").unwrap(); |
| 39 | cmd.args(&["run", "--root-dir", temp_dir.path().to_str().unwrap(), "test"]) | 39 | cmd.args(&[ |
| 40 | .assert() | 40 | "run", |
| 41 | .failure() | 41 | "--root-dir", |
| 42 | .stderr(predicate::str::contains("Command cannot be empty")); | 42 | temp_dir.path().to_str().unwrap(), |
| 43 | "test", | ||
| 44 | ]) | ||
| 45 | .assert() | ||
| 46 | .failure() | ||
| 47 | .stderr(predicate::str::contains("Command cannot be empty")); | ||
| 43 | } | 48 | } |
| 44 | 49 | ||
| 45 | #[test] | 50 | #[test] |
| @@ -47,10 +52,17 @@ fn test_run_creates_files() { | |||
| 47 | let temp_dir = TempDir::new().unwrap(); | 52 | let temp_dir = TempDir::new().unwrap(); |
| 48 | 53 | ||
| 49 | let mut cmd = Command::cargo_bin("demon").unwrap(); | 54 | let mut cmd = Command::cargo_bin("demon").unwrap(); |
| 50 | cmd.args(&["run", "--root-dir", temp_dir.path().to_str().unwrap(), "test", "echo", "hello"]) | 55 | cmd.args(&[ |
| 51 | .assert() | 56 | "run", |
| 52 | .success() | 57 | "--root-dir", |
| 53 | .stdout(predicate::str::contains("Started daemon 'test'")); | 58 | temp_dir.path().to_str().unwrap(), |
| 59 | "test", | ||
| 60 | "echo", | ||
| 61 | "hello", | ||
| 62 | ]) | ||
| 63 | .assert() | ||
| 64 | .success() | ||
| 65 | .stdout(predicate::str::contains("Started daemon 'test'")); | ||
| 54 | 66 | ||
| 55 | // Verify files were created | 67 | // Verify files were created |
| 56 | assert!(temp_dir.path().join("test.pid").exists()); | 68 | assert!(temp_dir.path().join("test.pid").exists()); |
| @@ -71,9 +83,16 @@ fn test_run_duplicate_process() { | |||
| 71 | 83 | ||
| 72 | // Start a long-running process | 84 | // Start a long-running process |
| 73 | let mut cmd = Command::cargo_bin("demon").unwrap(); | 85 | let mut cmd = Command::cargo_bin("demon").unwrap(); |
| 74 | cmd.args(&["run", "--root-dir", temp_dir.path().to_str().unwrap(), "long", "sleep", "30"]) | 86 | cmd.args(&[ |
| 75 | .assert() | 87 | "run", |
| 76 | .success(); | 88 | "--root-dir", |
| 89 | temp_dir.path().to_str().unwrap(), | ||
| 90 | "long", | ||
| 91 | "sleep", | ||
| 92 | "30", | ||
| 93 | ]) | ||
| 94 | .assert() | ||
| 95 | .success(); | ||
| 77 | 96 | ||
| 78 | // Try to start another with the same ID | 97 | // Try to start another with the same ID |
| 79 | let mut cmd = Command::cargo_bin("demon").unwrap(); | 98 | let mut cmd = Command::cargo_bin("demon").unwrap(); |
| @@ -267,9 +286,16 @@ fn test_clean_with_orphans() { | |||
| 267 | 286 | ||
| 268 | // Create a dead process | 287 | // Create a dead process |
| 269 | let mut cmd = Command::cargo_bin("demon").unwrap(); | 288 | let mut cmd = Command::cargo_bin("demon").unwrap(); |
| 270 | cmd.args(&["run", "--root-dir", temp_dir.path().to_str().unwrap(), "dead", "echo", "hello"]) | 289 | cmd.args(&[ |
| 271 | .assert() | 290 | "run", |
| 272 | .success(); | 291 | "--root-dir", |
| 292 | temp_dir.path().to_str().unwrap(), | ||
| 293 | "dead", | ||
| 294 | "echo", | ||
| 295 | "hello", | ||
| 296 | ]) | ||
| 297 | .assert() | ||
| 298 | .success(); | ||
| 273 | 299 | ||
| 274 | // Wait for process to complete | 300 | // Wait for process to complete |
| 275 | std::thread::sleep(Duration::from_millis(100)); | 301 | std::thread::sleep(Duration::from_millis(100)); |
| @@ -300,14 +326,14 @@ fn test_clean_removes_stdout_stderr_files() { | |||
| 300 | // Create a process that outputs to both stdout and stderr | 326 | // Create a process that outputs to both stdout and stderr |
| 301 | let mut cmd = Command::cargo_bin("demon").unwrap(); | 327 | let mut cmd = Command::cargo_bin("demon").unwrap(); |
| 302 | cmd.args(&[ | 328 | cmd.args(&[ |
| 303 | "run", | 329 | "run", |
| 304 | "--root-dir", | 330 | "--root-dir", |
| 305 | temp_dir.path().to_str().unwrap(), | 331 | temp_dir.path().to_str().unwrap(), |
| 306 | "test_output", | 332 | "test_output", |
| 307 | "--", | 333 | "--", |
| 308 | "sh", | 334 | "sh", |
| 309 | "-c", | 335 | "-c", |
| 310 | "echo 'stdout content'; echo 'stderr content' >&2" | 336 | "echo 'stdout content'; echo 'stderr content' >&2", |
| 311 | ]) | 337 | ]) |
| 312 | .assert() | 338 | .assert() |
| 313 | .success(); | 339 | .success(); |
| @@ -319,7 +345,7 @@ fn test_clean_removes_stdout_stderr_files() { | |||
| 319 | assert!(temp_dir.path().join("test_output.pid").exists()); | 345 | assert!(temp_dir.path().join("test_output.pid").exists()); |
| 320 | assert!(temp_dir.path().join("test_output.stdout").exists()); | 346 | assert!(temp_dir.path().join("test_output.stdout").exists()); |
| 321 | assert!(temp_dir.path().join("test_output.stderr").exists()); | 347 | assert!(temp_dir.path().join("test_output.stderr").exists()); |
| 322 | 348 | ||
| 323 | let stdout_content = fs::read_to_string(temp_dir.path().join("test_output.stdout")).unwrap(); | 349 | let stdout_content = fs::read_to_string(temp_dir.path().join("test_output.stdout")).unwrap(); |
| 324 | let stderr_content = fs::read_to_string(temp_dir.path().join("test_output.stderr")).unwrap(); | 350 | let stderr_content = fs::read_to_string(temp_dir.path().join("test_output.stderr")).unwrap(); |
| 325 | assert!(stdout_content.contains("stdout content")); | 351 | assert!(stdout_content.contains("stdout content")); |
| @@ -343,16 +369,16 @@ fn test_clean_removes_stdout_stderr_files() { | |||
| 343 | fn test_default_demon_directory_creation() { | 369 | fn test_default_demon_directory_creation() { |
| 344 | // This test verifies that when no --root-dir is specified, | 370 | // This test verifies that when no --root-dir is specified, |
| 345 | // the system creates and uses a .demon subdirectory in the git root | 371 | // the system creates and uses a .demon subdirectory in the git root |
| 346 | 372 | ||
| 347 | // Create a temporary git repo | 373 | // Create a temporary git repo |
| 348 | let temp_dir = TempDir::new().unwrap(); | 374 | let temp_dir = TempDir::new().unwrap(); |
| 349 | let git_dir = temp_dir.path().join(".git"); | 375 | let git_dir = temp_dir.path().join(".git"); |
| 350 | std::fs::create_dir(&git_dir).unwrap(); | 376 | std::fs::create_dir(&git_dir).unwrap(); |
| 351 | 377 | ||
| 352 | // Change to the temp directory | 378 | // Change to the temp directory |
| 353 | let original_dir = std::env::current_dir().unwrap(); | 379 | let original_dir = std::env::current_dir().unwrap(); |
| 354 | std::env::set_current_dir(temp_dir.path()).unwrap(); | 380 | std::env::set_current_dir(temp_dir.path()).unwrap(); |
| 355 | 381 | ||
| 356 | // Restore directory when done | 382 | // Restore directory when done |
| 357 | struct DirGuard(PathBuf); | 383 | struct DirGuard(PathBuf); |
| 358 | impl Drop for DirGuard { | 384 | impl Drop for DirGuard { |
| @@ -361,17 +387,17 @@ fn test_default_demon_directory_creation() { | |||
| 361 | } | 387 | } |
| 362 | } | 388 | } |
| 363 | let _guard = DirGuard(original_dir); | 389 | let _guard = DirGuard(original_dir); |
| 364 | 390 | ||
| 365 | // Run a command without --root-dir to test default behavior | 391 | // Run a command without --root-dir to test default behavior |
| 366 | let mut cmd = Command::cargo_bin("demon").unwrap(); | 392 | let mut cmd = Command::cargo_bin("demon").unwrap(); |
| 367 | cmd.args(&["run", "default_test", "echo", "hello"]) | 393 | cmd.args(&["run", "default_test", "echo", "hello"]) |
| 368 | .assert() | 394 | .assert() |
| 369 | .success() | 395 | .success() |
| 370 | .stdout(predicate::str::contains("Started daemon 'default_test'")); | 396 | .stdout(predicate::str::contains("Started daemon 'default_test'")); |
| 371 | 397 | ||
| 372 | // Wait for process to complete | 398 | // Wait for process to complete |
| 373 | std::thread::sleep(Duration::from_millis(100)); | 399 | std::thread::sleep(Duration::from_millis(100)); |
| 374 | 400 | ||
| 375 | // Verify that .demon directory was created and files are in it | 401 | // Verify that .demon directory was created and files are in it |
| 376 | let demon_dir = temp_dir.path().join(".demon"); | 402 | let demon_dir = temp_dir.path().join(".demon"); |
| 377 | assert!(demon_dir.exists()); | 403 | assert!(demon_dir.exists()); |
| @@ -379,7 +405,7 @@ fn test_default_demon_directory_creation() { | |||
| 379 | assert!(demon_dir.join("default_test.pid").exists()); | 405 | assert!(demon_dir.join("default_test.pid").exists()); |
| 380 | assert!(demon_dir.join("default_test.stdout").exists()); | 406 | assert!(demon_dir.join("default_test.stdout").exists()); |
| 381 | assert!(demon_dir.join("default_test.stderr").exists()); | 407 | assert!(demon_dir.join("default_test.stderr").exists()); |
| 382 | 408 | ||
| 383 | // Verify the stdout content | 409 | // Verify the stdout content |
| 384 | let stdout_content = fs::read_to_string(demon_dir.join("default_test.stdout")).unwrap(); | 410 | let stdout_content = fs::read_to_string(demon_dir.join("default_test.stdout")).unwrap(); |
| 385 | assert_eq!(stdout_content.trim(), "hello"); | 411 | assert_eq!(stdout_content.trim(), "hello"); |
