diff --git a/backup/src/delta.rs b/backup/src/delta.rs index cc831ac..95ec391 100644 --- a/backup/src/delta.rs +++ b/backup/src/delta.rs @@ -110,20 +110,19 @@ impl Delta { out } - /// Given a chain of deltas, ordered from last to first, calculate the "contribution" for each - /// state. + /// Given a chain of deltas, calculate the "contribution" for each state. /// - /// The contribution of a delta in a given chain is defined as the parts of the state produced - /// by this chain that are actually provided by this delta. This comes down to calculating the - /// strict difference of this delta and all of its successive deltas. + /// For each delta, its contribution is the part of its added and removed files that isn't + /// overwritten by any of its following deltas. pub fn contributions(deltas: I) -> Vec where I: IntoIterator, + I::IntoIter: DoubleEndedIterator, I::Item: Borrow, { let mut contributions: Vec = Vec::new(); - let mut deltas = deltas.into_iter(); + let mut deltas = deltas.into_iter().rev(); if let Some(first_delta) = deltas.next() { // From last to first, we calculate the strict difference of the delta with the union of all its @@ -138,8 +137,7 @@ impl Delta { } } - // contributions.reverse(); - + contributions.reverse(); contributions } @@ -242,4 +240,56 @@ mod tests { let expected = Delta::default().with_added("dir_1", ["file1", "file2"]); assert_eq!(expected, b.union(&a)); } + + #[test] + fn test_difference() { + let a = Delta::default() + .with_added("dir1", ["file1", "file2"]) + .with_removed("dir1", ["file3", "file4"]); + let b = Delta::default() + .with_added("dir1", ["file1"]) + .with_removed("dir1", ["file3"]); + let expected = Delta::default() + .with_added("dir1", ["file2"]) + .with_removed("dir1", ["file4"]); + + assert_eq!(a.difference(&b), expected); + assert_eq!(b.difference(&a), Delta::default()); + } + + #[test] + fn test_strict_difference() { + let a = Delta::default() + .with_added("dir1", ["file1", "file2"]) + .with_removed("dir1", ["file3", "file4"]); + let b = Delta::default() + .with_added("dir1", ["file1", "file4"]) + .with_removed("dir1", ["file3"]); + let expected = Delta::default().with_added("dir1", ["file2"]); + + assert_eq!(a.strict_difference(&b), expected); + assert_eq!(b.strict_difference(&a), Delta::default()); + } + + #[test] + fn test_contributions() { + let deltas = [ + Delta::default().with_added("dir1", ["file4"]), + Delta::default().with_added("dir1", ["file1", "file2"]), + Delta::default() + .with_added("dir1", ["file1"]) + .with_added("dir2", ["file3"]), + Delta::default() + .with_added("dir1", ["file2"]) + .with_removed("dir2", ["file3"]), + ]; + let expected = [ + State::default().with_dir("dir1", ["file4"]), + State::default(), + State::default().with_dir("dir1", ["file1"]), + State::default().with_dir("dir1", ["file2"]), + ]; + + assert_eq!(Delta::contributions(deltas), expected); + } } diff --git a/backup/src/manager/mod.rs b/backup/src/manager/mod.rs index f8bbc73..f13c69f 100644 --- a/backup/src/manager/mod.rs +++ b/backup/src/manager/mod.rs @@ -229,9 +229,8 @@ where .map(|_| ()), // Incremental backups are exported one by one according to their contribution BackupType::Incremental => { - let contributions = Delta::contributions( - chain.iter().take(index + 1).map(|b| &b.delta).rev(), - ); + let contributions = + Delta::contributions(chain.iter().take(index + 1).map(|b| &b.delta)); let tar_gz = OpenOptions::new() .write(true) @@ -245,7 +244,6 @@ where // overwritten by their successors anyways. for (contribution, backup) in contributions .iter() - .rev() .zip(chain.iter().take(index + 1)) .filter(|(contribution, _)| !contribution.is_empty()) {