From bbfd0cd4643fc0f589cf4d7f5cc74af17617e8e7 Mon Sep 17 00:00:00 2001 From: Alexander Weiss Date: Fri, 7 Jul 2023 15:40:21 +0200 Subject: [PATCH] refactor ls command --- crates/rustic_core/examples/ls.rs | 33 +++++++++++++++++++ crates/rustic_core/src/blob/tree.rs | 40 +++++++++++++++-------- crates/rustic_core/src/repository.rs | 13 ++++++-- src/commands/ls.rs | 47 +++++----------------------- src/commands/restore.rs | 4 +-- 5 files changed, 81 insertions(+), 56 deletions(-) create mode 100644 crates/rustic_core/examples/ls.rs diff --git a/crates/rustic_core/examples/ls.rs b/crates/rustic_core/examples/ls.rs new file mode 100644 index 000000000..f45b674f5 --- /dev/null +++ b/crates/rustic_core/examples/ls.rs @@ -0,0 +1,33 @@ +//! `ls` example +use rustic_core::{Repository, RepositoryOptions, TreeStreamerOptions}; +use simplelog::{Config, LevelFilter, SimpleLogger}; + +fn main() { + // Display info logs + let _ = SimpleLogger::init(LevelFilter::Info, Config::default()); + + // Open repository + let repo_opts = RepositoryOptions { + repository: Some("/tmp/repo".to_string()), + password: Some("test".to_string()), + ..Default::default() + }; + + let repo = Repository::new(&repo_opts) + .unwrap() + .open() + .unwrap() + .to_indexed() + .unwrap(); + + // use latest snapshot without filtering snapshots + let node = repo.node_from_snapshot_path("latest", |_| true).unwrap(); + + // 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).unwrap() { + let (path, _) = item.unwrap(); + println!("{path:?} "); + } +} diff --git a/crates/rustic_core/src/blob/tree.rs b/crates/rustic_core/src/blob/tree.rs index 8b767e9f0..47ddab465 100644 --- a/crates/rustic_core/src/blob/tree.rs +++ b/crates/rustic_core/src/blob/tree.rs @@ -158,6 +158,7 @@ where path: PathBuf, be: BE, overrides: Option, + recursive: bool, } impl NodeStreamer @@ -165,10 +166,15 @@ where BE: IndexedBackend, { pub fn new(be: BE, node: &Node) -> RusticResult { - Self::new_streamer(be, node, None) + Self::new_streamer(be, node, None, true) } - fn new_streamer(be: BE, node: &Node, overrides: Option) -> RusticResult { + fn new_streamer( + be: BE, + node: &Node, + overrides: Option, + recursive: bool, + ) -> RusticResult { let inner = if node.is_dir() { Tree::from_backend(&be, node.subtree.unwrap())? .nodes @@ -182,10 +188,16 @@ where path: PathBuf::new(), be, overrides, + recursive, }) } - pub fn new_with_glob(be: BE, node: &Node, opts: &TreeStreamerOptions) -> RusticResult { + pub fn new_with_glob( + be: BE, + node: &Node, + opts: &TreeStreamerOptions, + recursive: bool, + ) -> RusticResult { let mut override_builder = OverrideBuilder::new("/"); for g in &opts.glob { @@ -228,7 +240,7 @@ where .build() .map_err(TreeErrorKind::BuildingNodeStreamerFailed)?; - Self::new_streamer(be, node, Some(overrides)) + Self::new_streamer(be, node, Some(overrides), recursive) } } @@ -246,15 +258,17 @@ where match self.inner.next() { Some(node) => { let path = self.path.join(node.name()); - if let Some(id) = node.subtree { - self.path.push(node.name()); - let be = self.be.clone(); - let tree = match Tree::from_backend(&be, id) { - Ok(tree) => tree, - Err(err) => return Some(Err(err)), - }; - let old_inner = mem::replace(&mut self.inner, tree.nodes.into_iter()); - self.open_iterators.push(old_inner); + if self.recursive { + if let Some(id) = node.subtree { + self.path.push(node.name()); + let be = self.be.clone(); + let tree = match Tree::from_backend(&be, id) { + Ok(tree) => tree, + Err(err) => return Some(Err(err)), + }; + let old_inner = mem::replace(&mut self.inner, tree.nodes.into_iter()); + self.open_iterators.push(old_inner); + } } if let Some(overrides) = &self.overrides { diff --git a/crates/rustic_core/src/repository.rs b/crates/rustic_core/src/repository.rs index 2fd430e87..a86c85621 100644 --- a/crates/rustic_core/src/repository.rs +++ b/crates/rustic_core/src/repository.rs @@ -39,8 +39,8 @@ use crate::{ error::{KeyFileErrorKind, RepositoryErrorKind, RusticErrorKind}, repofile::{configfile::ConfigFile, keyfile::find_key_in_backend}, BlobType, DecryptFullBackend, Id, IndexBackend, IndexedBackend, NoProgressBars, Node, - ProgressBars, PruneOpts, PrunePlan, RusticResult, SnapshotFile, SnapshotGroup, - SnapshotGroupCriterion, Tree, + NodeStreamer, ProgressBars, PruneOpts, PrunePlan, RusticResult, SnapshotFile, SnapshotGroup, + SnapshotGroupCriterion, Tree, TreeStreamerOptions, }; mod warm_up; @@ -607,4 +607,13 @@ impl Repository { pub fn dump(&self, node: &Node, w: &mut impl Write) -> RusticResult<()> { commands::dump::dump(self, node, w) } + + pub fn ls( + &self, + node: &Node, + streamer_opts: &TreeStreamerOptions, + recursive: bool, + ) -> RusticResult>> { + NodeStreamer::new_with_glob(self.index().clone(), node, streamer_opts, recursive) + } } diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 9714f1b88..beb8c33c1 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -7,11 +7,7 @@ use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; use anyhow::Result; -use std::path::Path; - -use rustic_core::{ - IndexBackend, NodeStreamer, Open, ProgressBars, SnapshotFile, Tree, TreeStreamerOptions, -}; +use rustic_core::TreeStreamerOptions; /// `ls` subcommand #[derive(clap::Parser, Command, Debug)] @@ -40,44 +36,17 @@ impl Runnable for LsCmd { impl LsCmd { fn inner_run(&self) -> Result<()> { let config = RUSTIC_APP.config(); - let progress_options = &config.global.progress_options; - let repo = open_repository(&config)?; + let repo = open_repository(&config)?.to_indexed()?; - let be = repo.dbe(); - let mut recursive = self.recursive; + let node = + repo.node_from_snapshot_path(&self.snap, |sn| config.snapshot_filter.matches(sn))?; - let (id, path) = self.snap.split_once(':').unwrap_or_else(|| { - recursive = true; - (&self.snap, "") - }); - let snap = SnapshotFile::from_str( - be, - id, - |sn| config.snapshot_filter.matches(sn), - &progress_options.progress_counter(""), - )?; - let index = IndexBackend::new(be, &progress_options.progress_counter(""))?; - let node = Tree::node_from_path(&index, snap.tree, Path::new(path))?; + let recursive = !self.snap.contains(':') || self.recursive; - if recursive { - NodeStreamer::new_with_glob(index, &node, &self.streamer_opts)?.for_each(|item| { - let (path, _) = match item { - Ok(it) => it, - Err(err) => { - status_err!("{}", err); - RUSTIC_APP.shutdown(Shutdown::Crash); - } - }; - println!("{path:?} "); - }); - } else if node.is_dir() { - let tree = Tree::from_backend(&index, node.subtree.unwrap())?.nodes; - for node in tree { - println!("{:?} ", node.name()); - } - } else { - println!("{:?} ", node.name()); + for item in repo.ls(&node, &self.streamer_opts, recursive)? { + let (path, _) = item?; + println!("{path:?} "); } Ok(()) diff --git a/src/commands/restore.rs b/src/commands/restore.rs index 5f9924b14..067d67263 100644 --- a/src/commands/restore.rs +++ b/src/commands/restore.rs @@ -278,7 +278,7 @@ impl RestoreCmd { let mut next_dst = dst_iter.next(); let mut node_streamer = - NodeStreamer::new_with_glob(index.clone(), node, &self.streamer_opts.clone())?; + NodeStreamer::new_with_glob(index.clone(), node, &self.streamer_opts.clone(), true)?; let mut next_node = node_streamer.next().transpose()?; loop { @@ -344,7 +344,7 @@ impl RestoreCmd { ) -> Result<()> { // walk over tree in repository and compare with tree in dest let mut node_streamer = - NodeStreamer::new_with_glob(index, node, &self.streamer_opts.clone())?; + NodeStreamer::new_with_glob(index, node, &self.streamer_opts.clone(), true)?; let mut dir_stack = Vec::new(); while let Some((path, node)) = node_streamer.next().transpose()? { match node.node_type {