use std::path::Path; use std::process::Command; use crate::sync::error::{SyncError, SyncResult}; pub async fn run_gc(repo_dir: &Path) { let dir_str = repo_dir.display().to_string(); let dir = repo_dir.to_path_buf(); let result = tokio::task::spawn_blocking(move || { let _ = run_git(&dir, &["gc", "--prune=now", "--quiet"]); }) .await .map_err(|e| SyncError::Internal(format!("join error: {e}"))); if let Err(e) = result { tracing::warn!(repo_dir = %dir_str, error = %e, "git gc failed"); } } pub async fn run_fsck(repo_dir: &Path) { let dir_str = repo_dir.display().to_string(); let dir = repo_dir.to_path_buf(); let result = tokio::task::spawn_blocking(move || run_git(&dir, &["fsck", "--no-progress"])) .await .map_err(|e| SyncError::Internal(format!("join error: {e}"))); match result { Ok(Ok(stdout)) if stdout.contains("error") || stdout.contains("broken") => { tracing::warn!( repo_dir = %dir_str, output = %stdout.trim(), "fsck reported integrity issues" ); } Ok(_) => {} Err(e) => { tracing::warn!(repo_dir = %dir_str, error = %e, "fsck failed"); } } } fn run_git(repo_dir: &Path, args: &[&str]) -> SyncResult { let output = Command::new("git") .arg("-C") .arg(repo_dir) .args(args) .output() .map_err(|e| SyncError::Internal(format!("spawn git: {e}")))?; if !output.status.success() { return Err(SyncError::Internal(format!( "git {} exited {}: {}", args.join(" "), output.status.code().unwrap_or(-1), String::from_utf8_lossy(&output.stderr).trim() ))); } Ok(String::from_utf8_lossy(&output.stdout).into_owned()) }