use super::super::ScopeFileSystem;
use crate::{Error, Result};
const COMMIT_LOCK_FILE: &str = "commit.lock";
#[derive(Debug, PartialEq, Eq)]
pub struct CommitLock {
added_files: Vec<String>,
removed_files: Vec<String>,
}
impl CommitLock {
pub fn new(added_files: Vec<String>, removed_files: Vec<String>) -> Self {
debug_assert!(!removed_files.iter().any(|item| added_files.contains(item)));
Self {
added_files,
removed_files,
}
}
pub async fn load(fs: &ScopeFileSystem) -> Result<Self> {
let mut reader = fs.stream_read(COMMIT_LOCK_FILE).await?;
let mut added_files = Vec::new();
let mut removed_files = Vec::new();
let mut current_section = None;
while let Ok(line) = reader.read_line().await {
if line.is_empty() {
break;
}
let line = line.trim();
if line.is_empty() {
continue;
}
match line {
"[ADD]" => current_section = Some("add"),
"[REMOVE]" => current_section = Some("remove"),
_ => match current_section {
Some("add") => added_files.push(line.to_string()),
Some("remove") => removed_files.push(line.to_string()),
None => {
return Err(Error::InvalidFormat(format!(
"Unexpected line in '{COMMIT_LOCK_FILE}' before section header: '{line}'"
)));
}
_ => unreachable!(),
},
}
}
Ok(Self {
added_files,
removed_files,
})
}
pub async fn save(&self, fs: &ScopeFileSystem) -> Result<()> {
let mut writer = fs.stream_write(COMMIT_LOCK_FILE).await?;
writer.write_line("[ADD]").await?;
for file in &self.added_files {
writer.write_line(file).await?;
}
writer.write_line("[REMOVE]").await?;
for file in &self.removed_files {
writer.write_line(file).await?;
}
writer.flush().await?;
Ok(())
}
pub fn removed_files(&self) -> &[String] {
&self.removed_files
}
pub fn added_files(&self) -> &[String] {
&self.added_files
}
}
#[cfg(test)]
mod tests {
use super::{CommitLock, Result, ScopeFileSystem};
#[tokio::test]
#[cfg_attr(miri, ignore)]
async fn test_commit_lock() -> Result<()> {
let fs = ScopeFileSystem::new_memory_fs("/bucket1".into());
fs.ensure_exist().await?;
assert!(CommitLock::load(&fs).await.is_err());
let lock = CommitLock::new(
vec!["file1".to_string(), "file2".to_string()],
vec!["file3".to_string()],
);
lock.save(&fs).await?;
let new_lock = CommitLock::load(&fs).await?;
assert_eq!(lock, new_lock);
Ok(())
}
}