use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::fs;
use std::path::PathBuf;
use anyhow::Context;
use anyhow::Result;
use crate::fixes::imports::ValidatedFixSet;
pub(super) struct SessionSnapshot {
originals: BTreeMap<PathBuf, String>,
}
impl SessionSnapshot {
pub(super) const fn new() -> Self {
Self {
originals: BTreeMap::new(),
}
}
pub(super) fn record(&mut self, fixes: &ValidatedFixSet) -> Result<()> {
for fix in fixes.iter() {
let Entry::Vacant(slot) = self.originals.entry(fix.path.clone()) else {
continue;
};
let text = fs::read_to_string(slot.key())
.with_context(|| format!("failed to read {}", slot.key().display()))?;
slot.insert(text);
}
Ok(())
}
pub(super) fn restore(&self) -> Result<()> {
let mut first_failure = None;
for (path, original) in &self.originals {
if let Err(err) = fs::write(path, original)
.with_context(|| format!("failed to restore {}", path.display()))
{
first_failure.get_or_insert(err);
}
}
first_failure.map_or(Ok(()), Err)
}
}
#[cfg(test)]
mod tests {
use std::fs;
use std::path::Path;
use anyhow::Result;
use tempfile::tempdir;
use super::SessionSnapshot;
use crate::fixes::imports::UseFix;
use crate::fixes::imports::ValidatedFixSet;
fn whole_file_rewrite(path: &Path, replacement: &str) -> Result<ValidatedFixSet> {
let end = fs::read_to_string(path)?.len();
ValidatedFixSet::try_from(vec![UseFix {
path: path.to_path_buf(),
start: 0,
end,
replacement: replacement.to_string(),
import_group: None,
}])
}
#[test]
fn restore_returns_files_to_their_state_before_the_first_pass() -> Result<()> {
let temp = tempdir()?;
let alpha = temp.path().join("alpha.rs");
let beta = temp.path().join("beta.rs");
fs::write(&alpha, "alpha pristine\n")?;
fs::write(&beta, "beta pristine\n")?;
let mut session_snapshot = SessionSnapshot::new();
session_snapshot.record(&whole_file_rewrite(&alpha, "alpha pass one\n")?)?;
fs::write(&alpha, "alpha pass one\n")?;
session_snapshot.record(&whole_file_rewrite(&alpha, "alpha pass two\n")?)?;
session_snapshot.record(&whole_file_rewrite(&beta, "beta pass two\n")?)?;
fs::write(&alpha, "alpha pass two\n")?;
fs::write(&beta, "beta pass two\n")?;
session_snapshot.restore()?;
assert_eq!(fs::read_to_string(&alpha)?, "alpha pristine\n");
assert_eq!(fs::read_to_string(&beta)?, "beta pristine\n");
Ok(())
}
}