use crate::errors::{CascadeError, Result};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SyncState {
pub stack_id: String,
pub stack_name: String,
pub original_branch: String,
pub target_base: String,
pub remaining_entry_ids: Vec<String>,
pub current_entry_id: String,
pub current_entry_branch: String,
pub current_temp_branch: String,
pub temp_branches: Vec<String>,
}
impl SyncState {
fn state_path(repo_root: &Path) -> Result<PathBuf> {
Ok(crate::git::resolve_git_dir(repo_root)?.join("CASCADE_SYNC_STATE"))
}
pub fn save(&self, repo_root: &Path) -> Result<()> {
let state_path = Self::state_path(repo_root)?;
let json = serde_json::to_string_pretty(self)
.map_err(|e| CascadeError::config(format!("Failed to serialize sync state: {e}")))?;
std::fs::write(&state_path, json)
.map_err(|e| CascadeError::config(format!("Failed to write sync state: {e}")))?;
tracing::debug!("Saved sync state to {:?}", state_path);
Ok(())
}
pub fn load(repo_root: &Path) -> Result<Self> {
let state_path = Self::state_path(repo_root)?;
if !state_path.exists() {
return Err(CascadeError::config(
"No in-progress sync found. Nothing to continue.".to_string(),
));
}
let json = std::fs::read_to_string(&state_path)
.map_err(|e| CascadeError::config(format!("Failed to read sync state: {e}")))?;
let state: Self = serde_json::from_str(&json)
.map_err(|e| CascadeError::config(format!("Failed to parse sync state: {e}")))?;
tracing::debug!("Loaded sync state from {:?}", state_path);
Ok(state)
}
pub fn delete(repo_root: &Path) -> Result<()> {
let state_path = Self::state_path(repo_root)?;
if state_path.exists() {
std::fs::remove_file(&state_path)
.map_err(|e| CascadeError::config(format!("Failed to delete sync state: {e}")))?;
tracing::debug!("Deleted sync state file");
}
Ok(())
}
pub fn exists(repo_root: &Path) -> bool {
crate::git::resolve_git_dir(repo_root)
.map(|d| d.join("CASCADE_SYNC_STATE").exists())
.unwrap_or(false)
}
}