diff --git a/crates/rustic_core/examples/ls.rs b/crates/rustic_core/examples/ls.rs index 414dd9262..ab156181c 100644 --- a/crates/rustic_core/examples/ls.rs +++ b/crates/rustic_core/examples/ls.rs @@ -1,5 +1,5 @@ //! `ls` example -use rustic_core::{Repository, RepositoryOptions, TreeStreamerOptions}; +use rustic_core::{LsOptions, Repository, RepositoryOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; @@ -17,9 +17,8 @@ fn main() -> Result<(), Box> { let node = repo.node_from_snapshot_path("latest", |_| true)?; // recursively list the snapshot contents using no additional filtering - let recursive = true; - let streamer_opts = TreeStreamerOptions::default(); - for item in repo.ls(&node, &streamer_opts, recursive)? { + let ls_opts = LsOptions::default(); + for item in repo.ls(&node, &ls_opts)? { let (path, _) = item?; println!("{path:?} "); } diff --git a/crates/rustic_core/examples/restore.rs b/crates/rustic_core/examples/restore.rs index 180b06c8f..085e5d3e4 100644 --- a/crates/rustic_core/examples/restore.rs +++ b/crates/rustic_core/examples/restore.rs @@ -1,7 +1,5 @@ //! `restore` example -use rustic_core::{ - LocalDestination, Repository, RepositoryOptions, RestoreOptions, TreeStreamerOptions, -}; +use rustic_core::{LocalDestination, LsOptions, Repository, RepositoryOptions, RestoreOptions}; use simplelog::{Config, LevelFilter, SimpleLogger}; use std::error::Error; @@ -19,9 +17,8 @@ fn main() -> Result<(), Box> { let node = repo.node_from_snapshot_path("latest", |_| true)?; // use list of the snapshot contents using no additional filtering - let recursive = true; - let streamer_opts = TreeStreamerOptions::default(); - let ls = repo.ls(&node, &streamer_opts, recursive)?; + let streamer_opts = LsOptions::default(); + let ls = repo.ls(&node, &streamer_opts)?; let destination = "./restore/"; // restore to this destination dir let create = true; // create destination dir, if it doesn't exist diff --git a/crates/rustic_core/src/blob/tree.rs b/crates/rustic_core/src/blob/tree.rs index 8f0bbdb2e..e837ac957 100644 --- a/crates/rustic_core/src/blob/tree.rs +++ b/crates/rustic_core/src/blob/tree.rs @@ -8,6 +8,8 @@ use std::{ }; use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; +use derivative::Derivative; +use derive_setters::Setters; use ignore::overrides::{Override, OverrideBuilder}; use ignore::Match; @@ -120,32 +122,40 @@ impl IntoIterator for Tree { } #[cfg_attr(feature = "clap", derive(clap::Parser))] -#[derive(Default, Clone, Debug)] +#[derive(Derivative, Clone, Debug, Setters)] +#[derivative(Default)] +#[setters(into)] +/// Options for listing the `Nodes` of a `Tree` pub struct TreeStreamerOptions { /// Glob pattern to exclude/include (can be specified multiple times) #[cfg_attr(feature = "clap", clap(long, help_heading = "Exclude options"))] - glob: Vec, + pub glob: Vec, /// Same as --glob pattern but ignores the casing of filenames #[cfg_attr( feature = "clap", clap(long, value_name = "GLOB", help_heading = "Exclude options") )] - iglob: Vec, + pub iglob: Vec, /// Read glob patterns to exclude/include from this file (can be specified multiple times) #[cfg_attr( feature = "clap", clap(long, value_name = "FILE", help_heading = "Exclude options") )] - glob_file: Vec, + pub glob_file: Vec, /// Same as --glob-file ignores the casing of filenames in patterns #[cfg_attr( feature = "clap", clap(long, value_name = "FILE", help_heading = "Exclude options") )] - iglob_file: Vec, + pub iglob_file: Vec, + + /// recursively list the dir + #[cfg_attr(feature = "clap", clap(long))] + #[derivative(Default(value = "true"))] + pub recursive: bool, } /// [`NodeStreamer`] recursively streams all nodes of a given tree including all subtrees in-order @@ -193,12 +203,7 @@ where }) } - pub fn new_with_glob( - be: BE, - node: &Node, - opts: &TreeStreamerOptions, - recursive: bool, - ) -> RusticResult { + pub fn new_with_glob(be: BE, node: &Node, opts: &TreeStreamerOptions) -> RusticResult { let mut override_builder = OverrideBuilder::new("/"); for g in &opts.glob { @@ -241,7 +246,7 @@ where .build() .map_err(TreeErrorKind::BuildingNodeStreamerFailed)?; - Self::new_streamer(be, node, Some(overrides), recursive) + Self::new_streamer(be, node, Some(overrides), opts.recursive) } } diff --git a/crates/rustic_core/src/lib.rs b/crates/rustic_core/src/lib.rs index ecb90d6e3..946493eed 100644 --- a/crates/rustic_core/src/lib.rs +++ b/crates/rustic_core/src/lib.rs @@ -109,7 +109,7 @@ pub use crate::{ node::latest_node, ReadSourceEntry, }, - blob::{tree::TreeStreamerOptions, Sum}, + blob::{tree::TreeStreamerOptions as LsOptions, Sum}, commands::{ backup::{BackupOptions, ParentOptions}, check::CheckOptions, diff --git a/crates/rustic_core/src/repository.rs b/crates/rustic_core/src/repository.rs index 7b30b022d..a74e31531 100644 --- a/crates/rustic_core/src/repository.rs +++ b/crates/rustic_core/src/repository.rs @@ -52,8 +52,8 @@ use crate::{ repofile::{ keyfile::find_key_in_backend, ConfigFile, RepoFile, SnapshotFile, SnapshotSummary, Tree, }, - Id, LocalDestination, NoProgressBars, PathList, ProgressBars, PruneOptions, PrunePlan, - RusticResult, SnapshotGroup, SnapshotGroupCriterion, TreeStreamerOptions, + Id, LocalDestination, LsOptions, NoProgressBars, PathList, ProgressBars, PruneOptions, + PrunePlan, RusticResult, SnapshotGroup, SnapshotGroupCriterion, }; mod warm_up; @@ -724,10 +724,9 @@ impl Repository { pub fn ls( &self, node: &Node, - streamer_opts: &TreeStreamerOptions, - recursive: bool, + ls_opts: &LsOptions, ) -> RusticResult> + Clone> { - NodeStreamer::new_with_glob(self.index().clone(), node, streamer_opts, recursive) + NodeStreamer::new_with_glob(self.index().clone(), node, ls_opts) } pub fn restore( diff --git a/src/commands/diff.rs b/src/commands/diff.rs index 01a1f58c4..bd595a1ca 100644 --- a/src/commands/diff.rs +++ b/src/commands/diff.rs @@ -13,7 +13,7 @@ use anyhow::{bail, Context, Result}; use rustic_core::{ repofile::{BlobType, Node, NodeType}, IndexedFull, LocalDestination, LocalSource, LocalSourceFilterOptions, LocalSourceSaveOptions, - ReadSourceEntry, Repository, RusticResult, TreeStreamerOptions, + LsOptions, ReadSourceEntry, Repository, RusticResult, }; /// `diff` subcommand @@ -69,8 +69,8 @@ impl DiffCmd { let node2 = repo.node_from_snapshot_and_path(snap2, path2)?; diff( - repo.ls(&node1, &TreeStreamerOptions::default(), true)?, - repo.ls(&node2, &TreeStreamerOptions::default(), true)?, + repo.ls(&node1, &LsOptions::default())?, + repo.ls(&node2, &LsOptions::default())?, self.no_content, |_path, node1, node2| Ok(node1.content == node2.content), self.metadata, @@ -106,7 +106,7 @@ impl DiffCmd { }); diff( - repo.ls(&node1, &TreeStreamerOptions::default(), true)?, + repo.ls(&node1, &LsOptions::default())?, src, self.no_content, |path, node1, _node2| identical_content_local(&local, &repo, path, node1), diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 8354d900d..56298ce68 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -11,7 +11,7 @@ use anyhow::Result; use rustic_core::{ repofile::{Node, NodeType}, - TreeStreamerOptions, + LsOptions, }; mod constants { @@ -37,10 +37,6 @@ pub(crate) struct LsCmd { #[clap(value_name = "SNAPSHOT[:PATH]")] snap: String, - /// recursively list the dir (default when no PATH is given) - #[clap(long)] - recursive: bool, - /// show summary #[clap(long, short = 's')] summary: bool, @@ -50,7 +46,7 @@ pub(crate) struct LsCmd { long: bool, #[clap(flatten)] - streamer_opts: TreeStreamerOptions, + ls_opts: LsOptions, } impl Runnable for LsCmd { @@ -91,11 +87,12 @@ impl LsCmd { repo.node_from_snapshot_path(&self.snap, |sn| config.snapshot_filter.matches(sn))?; // recursive if standard if we specify a snapshot without dirs. In other cases, use the parameter `recursive` - let recursive = !self.snap.contains(':') || self.recursive; + let mut ls_opts = self.ls_opts.clone(); + ls_opts.recursive = !self.snap.contains(':') || ls_opts.recursive; let mut summary = Summary::default(); - for item in repo.ls(&node, &self.streamer_opts, recursive)? { + for item in repo.ls(&node, &ls_opts)? { let (path, node) = item?; summary.update(&node); if self.long { diff --git a/src/commands/restore.rs b/src/commands/restore.rs index ddb76bdcf..703fee41b 100644 --- a/src/commands/restore.rs +++ b/src/commands/restore.rs @@ -10,7 +10,7 @@ use abscissa_core::{Command, Runnable, Shutdown}; use anyhow::Result; use log::info; -use rustic_core::{LocalDestination, RestoreOptions, TreeStreamerOptions}; +use rustic_core::{LocalDestination, LsOptions, RestoreOptions}; use crate::filtering::SnapshotFilter; @@ -30,7 +30,7 @@ pub(crate) struct RestoreCmd { opts: RestoreOptions, #[clap(flatten)] - streamer_opts: TreeStreamerOptions, + ls_opts: LsOptions, #[clap( flatten, @@ -55,7 +55,11 @@ impl RestoreCmd { let node = repo.node_from_snapshot_path(&self.snap, |sn| config.snapshot_filter.matches(sn))?; - let ls = repo.ls(&node, &self.streamer_opts, true)?; + + // for restore, always recurse into tree + let mut ls_opts = self.ls_opts.clone(); + ls_opts.recursive = true; + let ls = repo.ls(&node, &ls_opts)?; let dest = LocalDestination::new(&self.dest, true, !node.is_dir())?;