use std::path::PathBuf;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use crate::config::Config;
use crate::progress::sanitize_label;
#[derive(Debug, Serialize, Deserialize)]
pub struct Checkpoint {
#[serde(rename = "completedTenants", default)]
pub completed_tenants: Vec<String>,
#[serde(rename = "startedAt")]
pub started_at: String,
#[serde(rename = "updatedAt")]
pub updated_at: String,
#[serde(skip)]
path: PathBuf,
}
pub fn path_for(cfg: &Config) -> PathBuf {
let allowlist_driving = cfg
.tenant_allowlist
.as_ref()
.is_some_and(|a| !a.is_empty());
match (&cfg.tenant_id, allowlist_driving) {
(Some(id), false) => PathBuf::from(format!(
"./purge-checkpoint-{}.json",
sanitize_label(id)
)),
_ => PathBuf::from("./purge-checkpoint.json"),
}
}
impl Checkpoint {
pub fn load(cfg: &Config) -> Self {
let path = path_for(cfg);
let now = chrono::Utc::now().to_rfc3339();
match std::fs::read_to_string(&path)
.ok()
.and_then(|s| serde_json::from_str::<Checkpoint>(&s).ok())
{
Some(mut cp) => {
cp.path = path;
cp
}
None => Checkpoint {
completed_tenants: Vec::new(),
started_at: now.clone(),
updated_at: now,
path,
},
}
}
pub fn save(&mut self) -> Result<()> {
self.updated_at = chrono::Utc::now().to_rfc3339();
let json = serde_json::to_string_pretty(self)?;
std::fs::write(&self.path, json)
.with_context(|| format!("could not write checkpoint {}", self.path.display()))
}
pub fn remove(&self) {
let _ = std::fs::remove_file(&self.path);
}
pub fn contains(&self, tenant: &str) -> bool {
self.completed_tenants.iter().any(|t| t == tenant)
}
pub fn display_path(&self) -> String {
self.path.display().to_string()
}
}