Skip to content

Commit 6ef4d5a

Browse files
authored
feat(core): repository APIs to identify snapshots using latest~N (#426)
1 parent 59ad1df commit 6ef4d5a

File tree

9 files changed

+255
-34
lines changed

9 files changed

+255
-34
lines changed

crates/backend/src/rclone.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ impl RcloneBackend {
178178
let user = Alphanumeric.sample_string(&mut rng(), 12);
179179
let password = Alphanumeric.sample_string(&mut rng(), 12);
180180

181-
let mut rclone_command = rclone_command.map_or(DEFAULT_COMMAND.to_string(), Clone::clone);
181+
let mut rclone_command =
182+
rclone_command.map_or_else(|| DEFAULT_COMMAND.to_string(), Clone::clone);
182183
rclone_command.push(' ');
183184
rclone_command.push_str(url.as_ref());
184185
let rclone_command: CommandInput = rclone_command.parse().map_err(

crates/core/src/commands/forget.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub(crate) fn get_forget_snapshots<P: ProgressBars, S: Open>(
8181
repo: &Repository<P, S>,
8282
keep: &KeepOptions,
8383
group_by: SnapshotGroupCriterion,
84-
filter: impl FnMut(&SnapshotFile) -> bool,
84+
filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
8585
) -> RusticResult<ForgetGroups> {
8686
let now = Local::now();
8787

crates/core/src/commands/snapshots.rs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
//! `smapshot` subcommand
1+
//! `snapshot` subcommand
2+
3+
use itertools::Itertools;
24

35
use crate::{
46
Progress,
@@ -22,6 +24,7 @@ use crate::{
2224
///
2325
/// * `repo` - The repository to get the snapshots from.
2426
/// * `ids` - The ids of the snapshots to get.
27+
/// * each `id` can use an actual (short) id "01a2b3c4" or "latest" or "latest~N"
2528
/// * `group_by` - The criterion to group the snapshots by.
2629
/// * `filter` - The filter to apply to the snapshots.
2730
///
@@ -32,30 +35,23 @@ pub(crate) fn get_snapshot_group<P: ProgressBars, S: Open>(
3235
repo: &Repository<P, S>,
3336
ids: &[String],
3437
group_by: SnapshotGroupCriterion,
35-
filter: impl FnMut(&SnapshotFile) -> bool,
38+
filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
3639
) -> RusticResult<Vec<(SnapshotGroup, Vec<SnapshotFile>)>> {
3740
let pb = &repo.pb;
3841
let dbe = repo.dbe();
3942
let p = pb.progress_counter("getting snapshots...");
40-
let groups = match ids {
41-
[] => SnapshotFile::group_from_backend(dbe, filter, group_by, &p)?,
42-
[id] if id == "latest" => SnapshotFile::group_from_backend(dbe, filter, group_by, &p)?
43+
let groups = if ids.is_empty() {
44+
SnapshotFile::group_from_backend(dbe, filter, group_by, &p)?
45+
} else {
46+
let snaps = SnapshotFile::from_strs(dbe, ids, filter, &p)?;
47+
let mut result = Vec::new();
48+
for (group, snaps) in &snaps
4349
.into_iter()
44-
.map(|(group, mut snaps)| {
45-
snaps.sort_unstable();
46-
let last_idx = snaps.len() - 1;
47-
snaps.swap(0, last_idx);
48-
snaps.truncate(1);
49-
(group, snaps)
50-
})
51-
.collect::<Vec<_>>(),
52-
_ => {
53-
let item = (
54-
SnapshotGroup::default(),
55-
SnapshotFile::from_ids(dbe, ids, &p)?,
56-
);
57-
vec![item]
50+
.chunk_by(|sn| SnapshotGroup::from_snapshot(sn, group_by))
51+
{
52+
result.push((group, snaps.collect()));
5853
}
54+
result
5955
};
6056
p.finish();
6157

crates/core/src/error.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ pub struct RusticError {
173173
context: EcoVec<(EcoString, EcoString)>,
174174

175175
/// Chain to the cause of the error.
176-
source: Option<Box<(dyn std::error::Error + Send + Sync)>>,
176+
source: Option<Box<dyn std::error::Error + Send + Sync>>,
177177

178178
/// Severity of the error.
179179
severity: Option<Severity>,
@@ -346,7 +346,7 @@ impl RusticError {
346346
pub fn with_source(
347347
kind: ErrorKind,
348348
guidance: impl Into<EcoString>,
349-
source: impl Into<Box<(dyn std::error::Error + Send + Sync)>>,
349+
source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
350350
) -> Box<Self> {
351351
Self::new(kind, guidance).attach_source(source)
352352
}
@@ -445,7 +445,7 @@ impl RusticError {
445445
/// Attach a chain to the cause of the error.
446446
pub fn attach_source(
447447
self,
448-
value: impl Into<Box<(dyn std::error::Error + Send + Sync)>>,
448+
value: impl Into<Box<dyn std::error::Error + Send + Sync>>,
449449
) -> Box<Self> {
450450
Box::new(Self {
451451
source: Some(value.into()),

crates/core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ pub use crate::{
153153
PathList, SnapshotGroup, SnapshotGroupCriterion, SnapshotOptions, StringList,
154154
},
155155
repository::{
156-
FullIndex, IndexedFull, IndexedIds, IndexedStatus, IndexedTree, Open, OpenStatus,
156+
FullIndex, IdIndex, IndexedFull, IndexedIds, IndexedStatus, IndexedTree, Open, OpenStatus,
157157
Repository, RepositoryOptions,
158158
command_input::{CommandInput, CommandInputErrorKind},
159159
},

crates/core/src/repofile/configfile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub struct ConfigFile {
5353
/// Repository version. Currently 1 and 2 are supported
5454
pub version: u32,
5555

56-
/// The [`Id`] identifying the repsitory
56+
/// The [`Id`] identifying the repository
5757
pub id: RepositoryId,
5858

5959
/// The chunker polynomial used to chunk data

crates/core/src/repository.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ impl<P: ProgressBars, S: Open> Repository<P, S> {
938938
&self,
939939
ids: &[String],
940940
group_by: SnapshotGroupCriterion,
941-
filter: impl FnMut(&SnapshotFile) -> bool,
941+
filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
942942
) -> RusticResult<Vec<(SnapshotGroup, Vec<SnapshotFile>)>> {
943943
commands::snapshots::get_snapshot_group(self, ids, group_by, filter)
944944
}
@@ -959,7 +959,7 @@ impl<P: ProgressBars, S: Open> Repository<P, S> {
959959
/// # Returns
960960
///
961961
/// If `id` is (part of) an `Id`, return this snapshot.
962-
/// If `id` is "latest", return the latest snapshot respecting the giving filter.
962+
/// If `id` is "latest" or "latest~N", return the latest (or Nth latest) snapshot respecting the giving filter.
963963
pub fn get_snapshot_from_str(
964964
&self,
965965
id: &str,
@@ -971,6 +971,35 @@ impl<P: ProgressBars, S: Open> Repository<P, S> {
971971
Ok(snap)
972972
}
973973

974+
/// Get a single snapshot
975+
///
976+
/// # Arguments
977+
///
978+
/// * `ids` - The ids of the snapshot to get
979+
/// * each `id` can use an actual (short) id "01a2b3c4" or "latest" or "latest~N"
980+
/// * `filter` - The filter to use
981+
///
982+
/// # Errors
983+
///
984+
/// * If the string is not a valid hexadecimal string
985+
/// * If no id could be found.
986+
/// * If the id is not unique.
987+
///
988+
/// # Returns
989+
///
990+
/// If `id` is (part of) an `Id`, return this snapshot.
991+
/// If `id` is "latest" or "latest~N", return the latest (or Nth latest) snapshot respecting the giving filter.
992+
pub fn get_snapshots_from_strs<T: AsRef<str>>(
993+
&self,
994+
ids: &[T],
995+
filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
996+
) -> RusticResult<Vec<SnapshotFile>> {
997+
let p = self.pb.progress_counter("getting snapshots...");
998+
let snaps = SnapshotFile::from_strs(self.dbe(), ids, filter, &p)?;
999+
p.finish();
1000+
Ok(snaps)
1001+
}
1002+
9741003
/// Get the given snapshots.
9751004
///
9761005
/// # Arguments
@@ -1104,7 +1133,7 @@ impl<P: ProgressBars, S: Open> Repository<P, S> {
11041133
&self,
11051134
keep: &KeepOptions,
11061135
group_by: SnapshotGroupCriterion,
1107-
filter: impl FnMut(&SnapshotFile) -> bool,
1136+
filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
11081137
) -> RusticResult<ForgetGroups> {
11091138
commands::forget::get_forget_snapshots(self, keep, group_by, filter)
11101139
}

crates/core/tests/integration.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod integration {
3232
mod ls;
3333
mod prune;
3434
mod restore;
35+
mod snapshots;
3536
mod vfs;
3637
use super::*;
3738
}
@@ -100,11 +101,10 @@ fn insta_snapshotfile_redaction() -> Settings {
100101

101102
settings.add_redaction(".**.tree", "[tree_id]");
102103
settings.add_dynamic_redaction(".**.program_version", |val, _| {
103-
val.resolve_inner()
104-
.as_str()
105-
.map_or("[program_version]".to_string(), |v| {
106-
v.replace(env!("CARGO_PKG_VERSION"), "[rustic_core_version]")
107-
})
104+
val.resolve_inner().as_str().map_or_else(
105+
|| "[program_version]".to_string(),
106+
|v| v.replace(env!("CARGO_PKG_VERSION"), "[rustic_core_version]"),
107+
)
108108
});
109109
settings.add_redaction(".**.time", "[time]");
110110
settings.add_dynamic_redaction(".**.parent", handle_option);

0 commit comments

Comments
 (0)