87 lines
2.5 KiB
Rust
87 lines
2.5 KiB
Rust
//! State snapshots for rollback.
|
|
|
|
use super::store::{State, StateError};
|
|
use std::path::Path;
|
|
|
|
/// A named snapshot of doot state.
|
|
pub struct Snapshot {
|
|
pub name: String,
|
|
pub created_at: String,
|
|
pub state: State,
|
|
}
|
|
|
|
impl Snapshot {
|
|
/// Creates and saves a new snapshot.
|
|
pub fn create(name: &str, state: &State, snapshot_dir: &Path) -> Result<Self, StateError> {
|
|
let created_at = chrono_now();
|
|
let snapshot = Self {
|
|
name: name.to_string(),
|
|
created_at: created_at.clone(),
|
|
state: state.clone(),
|
|
};
|
|
|
|
snapshot.save(snapshot_dir)?;
|
|
Ok(snapshot)
|
|
}
|
|
|
|
/// Loads a snapshot by name.
|
|
pub fn load(name: &str, snapshot_dir: &Path) -> Result<Self, StateError> {
|
|
let path = snapshot_dir.join(format!("{}.json", name));
|
|
let content = std::fs::read_to_string(&path)?;
|
|
let state: State = serde_json::from_str(&content)?;
|
|
|
|
Ok(Self {
|
|
name: name.to_string(),
|
|
created_at: String::new(),
|
|
state,
|
|
})
|
|
}
|
|
|
|
/// Saves the snapshot to disk.
|
|
pub fn save(&self, snapshot_dir: &Path) -> Result<(), StateError> {
|
|
std::fs::create_dir_all(snapshot_dir)?;
|
|
let path = snapshot_dir.join(format!("{}.json", self.name));
|
|
let json = serde_json::to_string_pretty(&self.state)?;
|
|
std::fs::write(path, json)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Lists all snapshots.
|
|
pub fn list(snapshot_dir: &Path) -> Result<Vec<String>, StateError> {
|
|
if !snapshot_dir.exists() {
|
|
return Ok(Vec::new());
|
|
}
|
|
|
|
let mut snapshots = Vec::new();
|
|
for entry in std::fs::read_dir(snapshot_dir)? {
|
|
let entry = entry?;
|
|
let path = entry.path();
|
|
if path.extension().map(|e| e == "json").unwrap_or(false) {
|
|
if let Some(name) = path.file_stem() {
|
|
snapshots.push(name.to_string_lossy().to_string());
|
|
}
|
|
}
|
|
}
|
|
|
|
snapshots.sort();
|
|
Ok(snapshots)
|
|
}
|
|
|
|
/// Deletes a snapshot.
|
|
pub fn delete(name: &str, snapshot_dir: &Path) -> Result<(), StateError> {
|
|
let path = snapshot_dir.join(format!("{}.json", name));
|
|
if path.exists() {
|
|
std::fs::remove_file(path)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn chrono_now() -> String {
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
let secs = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_secs();
|
|
format!("{}", secs)
|
|
}
|