Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Repository method to update snapshot collections #260

Merged
merged 4 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 89 additions & 6 deletions crates/core/src/repofile/snapshotfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use crate::{
backend::{decrypt::DecryptReadBackend, FileType, FindInBackend},
blob::tree::TreeId,
error::{RusticError, RusticResult, SnapshotFileErrorKind},
error::{RusticError, RusticErrorKind, RusticResult, SnapshotFileErrorKind},
impl_repofile,
progress::Progress,
repofile::RepoFile,
Expand Down Expand Up @@ -550,14 +550,65 @@
be: &B,
ids: &[T],
p: &impl Progress,
) -> RusticResult<Vec<Self>> {
Self::update_from_ids(be, Vec::new(), ids, p)

Check warning on line 554 in crates/core/src/repofile/snapshotfile.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/repofile/snapshotfile.rs#L554

Added line #L554 was not covered by tests
}

/// Update a list of [`SnapshotFile`]s from the backend by supplying a list of/parts of their Ids
///
/// # Arguments
///
/// * `be` - The backend to use
/// * `ids` - The list of (parts of the) ids of the snapshots
/// * `p` - A progress bar to use
///
/// # Errors
///
/// * [`IdErrorKind::HexError`] - If the string is not a valid hexadecimal string
/// * [`BackendAccessErrorKind::NoSuitableIdFound`] - If no id could be found.
/// * [`BackendAccessErrorKind::IdNotUnique`] - If the id is not unique.
///
/// [`IdErrorKind::HexError`]: crate::error::IdErrorKind::HexError
/// [`BackendAccessErrorKind::NoSuitableIdFound`]: crate::error::BackendAccessErrorKind::NoSuitableIdFound
/// [`BackendAccessErrorKind::IdNotUnique`]: crate::error::BackendAccessErrorKind::IdNotUnique
pub(crate) fn update_from_ids<B: DecryptReadBackend, T: AsRef<str>>(
be: &B,
current: Vec<Self>,
ids: &[T],
p: &impl Progress,
) -> RusticResult<Vec<Self>> {
let ids = be.find_ids(FileType::Snapshot, ids)?;
let mut list: BTreeMap<_, _> =
be.stream_list::<Self>(&ids, p)?.into_iter().try_collect()?;
Self::fill_missing(be, current, &ids, |_| true, p)
}

// helper func
fn fill_missing<B, F>(
be: &B,
current: Vec<Self>,
ids: &[Id],
mut filter: F,
p: &impl Progress,
) -> RusticResult<Vec<Self>>
where
B: DecryptReadBackend,
F: FnMut(&Self) -> bool,
{
let mut snaps: BTreeMap<_, _> = current.into_iter().map(|snap| (snap.id, snap)).collect();
let missing_ids: Vec<_> = ids

Check warning on line 597 in crates/core/src/repofile/snapshotfile.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/repofile/snapshotfile.rs#L597

Added line #L597 was not covered by tests
.iter()
.filter(|id| !snaps.contains_key(&SnapshotId::from(**id)))
.copied()
.collect();
for res in be.stream_list::<Self>(&missing_ids, p)? {
let (id, snap) = res?;
if filter(&snap) {
let _ = snaps.insert(id, snap);
}
}
// sort back to original order
Ok(ids
.into_iter()
.filter_map(|id| list.remove_entry(&SnapshotId::from(id)))
.iter()

Check warning on line 610 in crates/core/src/repofile/snapshotfile.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/repofile/snapshotfile.rs#L610

Added line #L610 was not covered by tests
.filter_map(|id| snaps.remove_entry(&SnapshotId::from(*id)))
.map(Self::set_id)
.collect())
}
Expand Down Expand Up @@ -637,7 +688,22 @@
B: DecryptReadBackend,
F: FnMut(&Self) -> bool,
{
let mut snaps = Self::all_from_backend(be, filter, p)?;
Self::update_group_from_backend(be, Vec::new(), filter, crit, p)
}

pub(crate) fn update_group_from_backend<B, F>(
be: &B,
current: Vec<(SnapshotGroup, Vec<Self>)>,
filter: F,
crit: SnapshotGroupCriterion,
p: &impl Progress,
) -> RusticResult<Vec<(SnapshotGroup, Vec<Self>)>>
where
B: DecryptReadBackend,
F: FnMut(&Self) -> bool,
{
let current = current.into_iter().flat_map(|(_, snaps)| snaps).collect();

Check warning on line 705 in crates/core/src/repofile/snapshotfile.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/repofile/snapshotfile.rs#L705

Added line #L705 was not covered by tests
let mut snaps = Self::update_from_backend(be, current, filter, p)?;
snaps.sort_unstable_by(|sn1, sn2| sn1.cmp_group(crit, sn2));

let mut result = Vec::new();
Expand Down Expand Up @@ -668,6 +734,23 @@
.try_collect()
}

// TODO: add documentation!
pub(crate) fn update_from_backend<B, F>(
be: &B,
current: Vec<Self>,
filter: F,
p: &impl Progress,
) -> RusticResult<Vec<Self>>
where
B: DecryptReadBackend,
F: FnMut(&Self) -> bool,
{
let ids = be
.list(FileType::Snapshot)
.map_err(RusticErrorKind::Backend)?;

Check warning on line 750 in crates/core/src/repofile/snapshotfile.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/repofile/snapshotfile.rs#L749-L750

Added lines #L749 - L750 were not covered by tests
Self::fill_missing(be, current, &ids, filter, p)
}

/// Add tag lists to snapshot.
///
/// # Arguments
Expand Down
64 changes: 62 additions & 2 deletions crates/core/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,8 +949,31 @@
///
// TODO: Document errors
pub fn get_snapshots<T: AsRef<str>>(&self, ids: &[T]) -> RusticResult<Vec<SnapshotFile>> {
self.update_snapshots(Vec::new(), ids)
}

/// Update the given snapshots.
///
/// # Arguments
///
/// * `current` - The existing snapshots
/// * `ids` - The ids of the snapshots to get
///
/// # Notes
///
/// `ids` may contain part of snapshots id which will be resolved.
/// However, "latest" is not supported in this function.
///
/// # Errors
///
// TODO: Document errors
pub fn update_snapshots<T: AsRef<str>>(
&self,
current: Vec<SnapshotFile>,
ids: &[T],
) -> RusticResult<Vec<SnapshotFile>> {
let p = self.pb.progress_counter("getting snapshots...");
let result = SnapshotFile::from_ids(self.dbe(), ids, &p);
let result = SnapshotFile::update_from_ids(self.dbe(), current, ids, &p);
p.finish();
result
}
Expand All @@ -964,6 +987,22 @@
self.get_matching_snapshots(|_| true)
}

/// Update existing snapshots to all from the repository
///
/// # Arguments
///
/// * `current` - The existing snapshots
///
/// # Errors
///
// TODO: Document errors
pub fn update_all_snapshots(
&self,
current: Vec<SnapshotFile>,
) -> RusticResult<Vec<SnapshotFile>> {
self.update_matching_snapshots(current, |_| true)

Check warning on line 1003 in crates/core/src/repository.rs

View check run for this annotation

Codecov / codecov/patch

crates/core/src/repository.rs#L1003

Added line #L1003 was not covered by tests
}

/// Get all snapshots from the repository respecting the given `filter`
///
/// # Arguments
Expand All @@ -979,9 +1018,30 @@
pub fn get_matching_snapshots(
&self,
filter: impl FnMut(&SnapshotFile) -> bool,
) -> RusticResult<Vec<SnapshotFile>> {
self.update_matching_snapshots(Vec::new(), filter)
}

/// Update existing snapshots to all from the repository respecting the given `filter`
///
/// # Arguments
///
/// * `current` - The existing snapshots
/// * `filter` - The filter to use
///
/// # Errors
///
/// # Note
/// The result is not sorted and may come in random order!
///
// TODO: Document errors
pub fn update_matching_snapshots(
&self,
current: Vec<SnapshotFile>,
filter: impl FnMut(&SnapshotFile) -> bool,
) -> RusticResult<Vec<SnapshotFile>> {
let p = self.pb.progress_counter("getting snapshots...");
let result = SnapshotFile::all_from_backend(self.dbe(), filter, &p);
let result = SnapshotFile::update_from_backend(self.dbe(), current, filter, &p);
p.finish();
result
}
Expand Down
2 changes: 1 addition & 1 deletion crates/core/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ fn test_backup_with_tar_gz_passes(
// reverse order
all_snapshots.reverse();
ids.reverse();
let snaps = repo.get_snapshots(&ids)?;
let snaps = repo.update_snapshots(snaps, &ids)?;
assert_eq!(snaps, all_snapshots);

// get snapshot group
Expand Down