1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
// Conserve backup system.
// Copyright 2015-2023 Martin Pool.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//! Diff two trees: for example a live tree against a stored tree.
//!
//! See also [conserve::show_diff] to format the diff as text.
use readahead_iterator::IntoReadahead;
use crate::*;
#[derive(Debug)]
pub struct DiffOptions {
pub exclude: Exclude,
pub include_unchanged: bool,
// TODO: An option to filter to a subtree?
// TODO: Optionally compare all the content?
}
impl Default for DiffOptions {
fn default() -> Self {
DiffOptions {
exclude: Exclude::nothing(),
include_unchanged: false,
}
}
}
/// Generate an iter of per-entry diffs between two trees.
pub fn diff(
st: &StoredTree,
lt: &LiveTree,
options: &DiffOptions,
) -> Result<impl Iterator<Item = EntryChange>> {
let readahead = 1000;
let include_unchanged: bool = options.include_unchanged; // Copy out to avoid lifetime problems in the callback
let ait = st
.iter_entries(Apath::root(), options.exclude.clone())?
.readahead(readahead);
let bit = lt
.iter_entries(Apath::root(), options.exclude.clone())?
.filter(|le| le.kind() != Kind::Unknown)
.readahead(readahead);
Ok(MergeTrees::new(ait, bit)
.map(|me| me.to_entry_change())
.filter(move |c: &EntryChange| include_unchanged || !c.is_unchanged()))
}