mirror of
https://github.com/rustic-rs/rustic.git
synced 2025-10-26 11:18:51 +00:00
commit
f39e1e408b
33
crates/rustic_core/examples/ls.rs
Normal file
33
crates/rustic_core/examples/ls.rs
Normal file
@ -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:?} ");
|
||||
}
|
||||
}
|
||||
@ -158,6 +158,7 @@ where
|
||||
path: PathBuf,
|
||||
be: BE,
|
||||
overrides: Option<Override>,
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
impl<BE> NodeStreamer<BE>
|
||||
@ -165,10 +166,15 @@ where
|
||||
BE: IndexedBackend,
|
||||
{
|
||||
pub fn new(be: BE, node: &Node) -> RusticResult<Self> {
|
||||
Self::new_streamer(be, node, None)
|
||||
Self::new_streamer(be, node, None, true)
|
||||
}
|
||||
|
||||
fn new_streamer(be: BE, node: &Node, overrides: Option<Override>) -> RusticResult<Self> {
|
||||
fn new_streamer(
|
||||
be: BE,
|
||||
node: &Node,
|
||||
overrides: Option<Override>,
|
||||
recursive: bool,
|
||||
) -> RusticResult<Self> {
|
||||
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<Self> {
|
||||
pub fn new_with_glob(
|
||||
be: BE,
|
||||
node: &Node,
|
||||
opts: &TreeStreamerOptions,
|
||||
recursive: bool,
|
||||
) -> RusticResult<Self> {
|
||||
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 {
|
||||
|
||||
@ -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;
|
||||
@ -624,4 +624,13 @@ impl<P: ProgressBars, S: Indexed> Repository<P, S> {
|
||||
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<impl Iterator<Item = RusticResult<(PathBuf, Node)>>> {
|
||||
NodeStreamer::new_with_glob(self.index().clone(), node, streamer_opts, recursive)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(())
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user