use crate::app::rebase::{RebaseEntry, RebaseAction};
use std::path::{Path, PathBuf};
use std::fs;
use std::io;
#[derive(Debug, thiserror::Error)]
pub enum RebaseIOError {
#[error("IO error: {0}")]
Io(#[from] io::Error),
#[error("Invalid todo file format: {0}")]
InvalidFormat(String),
#[error("File operation failed: {0}")]
FileOperation(String),
}
pub struct RebaseIO;
impl RebaseIO {
pub fn format_todo_content(entries: &[RebaseEntry]) -> String {
entries
.iter()
.map(|entry| format!("{} {}", entry.action.as_str(), entry.hash))
.collect::<Vec<_>>()
.join("\n")
}
pub fn write_todo_atomically(
path: &Path,
content: &str,
) -> Result<(), RebaseIOError> {
let temp_path = path.with_extension("tmp");
fs::write(&temp_path, content)?;
fs::rename(temp_path, path)?;
Ok(())
}
pub fn read_todo_file(path: &Path) -> Result<Vec<RebaseEntry>, RebaseIOError> {
let content = fs::read_to_string(path)?;
let mut entries = Vec::new();
for line in content.lines() {
let line = line.trim();
if line.starts_with('#') || line.is_empty() {
continue;
}
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() < 2 {
continue; }
let action_str = parts[0];
let hash = parts[1].to_string();
let message = if parts.len() > 2 {
parts[2..].join(" ")
} else {
"Unknown commit".to_string()
};
let action = RebaseAction::from_str(action_str)
.unwrap_or(RebaseAction::Pick);
entries.push(RebaseEntry::new(hash, message, action));
}
Ok(entries)
}
pub fn find_todo_file(repo_path: &str) -> Option<PathBuf> {
let git_dir = Path::new(repo_path).join(".git");
let rebase_merge_todo = git_dir.join("rebase-merge").join("git-rebase-todo");
if rebase_merge_todo.exists() {
return Some(rebase_merge_todo);
}
let rebase_apply_todo = git_dir.join("rebase-apply").join("git-rebase-todo");
if rebase_apply_todo.exists() {
return Some(rebase_apply_todo);
}
None
}
pub fn is_rebase_in_progress(repo_path: &str) -> bool {
let git_dir = Path::new(repo_path).join(".git");
git_dir.join("rebase-merge").exists() || git_dir.join("rebase-apply").exists()
}
pub fn cleanup_rebase_directories(repo_path: &str) -> Result<(), RebaseIOError> {
let git_dir = Path::new(repo_path).join(".git");
let rebase_merge = git_dir.join("rebase-merge");
if rebase_merge.exists() {
fs::remove_dir_all(&rebase_merge)?;
}
let rebase_apply = git_dir.join("rebase-apply");
if rebase_apply.exists() {
fs::remove_dir_all(&rebase_apply)?;
}
Ok(())
}
}