cat/ls/restore: Add filtering for latest snapshot

This commit is contained in:
Alexander Weiss 2022-11-20 00:11:51 +01:00
parent bce9a13924
commit 3d73e2014d
4 changed files with 48 additions and 14 deletions

View File

@ -5,11 +5,12 @@ use clap::{Parser, Subcommand};
use indicatif::ProgressBar;
use super::progress_counter;
use super::rustic_config::RusticConfig;
use crate::backend::{DecryptReadBackend, FileType};
use crate::blob::{BlobType, Tree};
use crate::id::Id;
use crate::index::{IndexBackend, IndexedBackend};
use crate::repo::SnapshotFile;
use crate::repo::{SnapshotFile, SnapshotFilter};
#[derive(Parser)]
pub(super) struct Opts {
@ -41,12 +42,19 @@ struct IdOpt {
#[derive(Parser)]
struct TreeOpts {
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
filter: SnapshotFilter,
/// Snapshot/path of the tree to display
#[clap(value_name = "SNAPSHOT[:PATH]")]
snap: String,
}
pub(super) fn execute(be: &impl DecryptReadBackend, opts: Opts) -> Result<()> {
pub(super) fn execute(
be: &impl DecryptReadBackend,
opts: Opts,
config_file: RusticConfig,
) -> Result<()> {
match opts.command {
Command::Config => cat_file(be, FileType::Config, IdOpt::default()),
Command::Index(opt) => cat_file(be, FileType::Index, opt),
@ -55,7 +63,7 @@ pub(super) fn execute(be: &impl DecryptReadBackend, opts: Opts) -> Result<()> {
Command::TreeBlob(opt) => cat_blob(be, BlobType::Tree, opt),
Command::DataBlob(opt) => cat_blob(be, BlobType::Data, opt),
// special treatment for cating a tree within a snapshot
Command::Tree(opts) => cat_tree(be, opts),
Command::Tree(opts) => cat_tree(be, opts, config_file),
}
}
@ -75,9 +83,15 @@ fn cat_blob(be: &impl DecryptReadBackend, tpe: BlobType, opt: IdOpt) -> Result<(
Ok(())
}
fn cat_tree(be: &impl DecryptReadBackend, opts: TreeOpts) -> Result<()> {
fn cat_tree(
be: &impl DecryptReadBackend,
mut opts: TreeOpts,
config_file: RusticConfig,
) -> Result<()> {
config_file.merge_into("snapshot-filter", &mut opts.filter)?;
let (id, path) = opts.snap.split_once(':').unwrap_or((&opts.snap, ""));
let snap = SnapshotFile::from_str(be, id, |_| true, progress_counter(""))?;
let snap = SnapshotFile::from_str(be, id, |sn| sn.matches(&opts.filter), progress_counter(""))?;
let index = IndexBackend::new(be, progress_counter(""))?;
let id = Tree::subtree_id(&index, snap.tree, Path::new(path))?;
let data = index.blob_from_backend(&BlobType::Tree, &id)?;

View File

@ -3,21 +3,31 @@ use clap::Parser;
use std::path::Path;
use super::progress_counter;
use super::rustic_config::RusticConfig;
use crate::backend::DecryptReadBackend;
use crate::blob::{NodeStreamer, Tree};
use crate::index::IndexBackend;
use crate::repo::SnapshotFile;
use crate::repo::{SnapshotFile, SnapshotFilter};
#[derive(Parser)]
pub(super) struct Opts {
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
filter: SnapshotFilter,
/// Snapshot/path to list
#[clap(value_name = "SNAPSHOT[:PATH]")]
snap: String,
}
pub(super) fn execute(be: &(impl DecryptReadBackend + Unpin), opts: Opts) -> Result<()> {
pub(super) fn execute(
be: &impl DecryptReadBackend,
mut opts: Opts,
config_file: RusticConfig,
) -> Result<()> {
config_file.merge_into("snapshot-filter", &mut opts.filter)?;
let (id, path) = opts.snap.split_once(':').unwrap_or((&opts.snap, ""));
let snap = SnapshotFile::from_str(be, id, |_| true, progress_counter(""))?;
let snap = SnapshotFile::from_str(be, id, |sn| sn.matches(&opts.filter), progress_counter(""))?;
let index = IndexBackend::new(be, progress_counter(""))?;
let tree = Tree::subtree_id(&index, snap.tree, Path::new(path))?;

View File

@ -309,7 +309,7 @@ pub fn execute() -> Result<()> {
match cmd {
Command::Backup(opts) => backup::execute(&dbe, opts, config, config_file, command)?,
Command::Config(opts) => config::execute(&dbe, &be_hot, opts, config)?,
Command::Cat(opts) => cat::execute(&dbe, opts)?,
Command::Cat(opts) => cat::execute(&dbe, opts, config_file)?,
Command::Check(opts) => check::execute(&dbe, &cache, &be_hot, &be, opts)?,
Command::Completions(_) => {} // already handled above
Command::Diff(opts) => diff::execute(&dbe, opts)?,
@ -317,11 +317,11 @@ pub fn execute() -> Result<()> {
Command::Init(_) => {} // already handled above
Command::Key(opts) => key::execute(&dbe, key, opts)?,
Command::List(opts) => list::execute(&dbe, opts)?,
Command::Ls(opts) => ls::execute(&dbe, opts)?,
Command::Ls(opts) => ls::execute(&dbe, opts, config_file)?,
Command::SelfUpdate(_) => {} // already handled above
Command::Snapshots(opts) => snapshots::execute(&dbe, opts, config_file)?,
Command::Prune(opts) => prune::execute(&dbe, cache, opts, config, vec![])?,
Command::Restore(opts) => restore::execute(&dbe, opts)?,
Command::Restore(opts) => restore::execute(&dbe, opts, config_file)?,
Command::Repair(opts) => repair::execute(&dbe, opts, config_file, &config)?,
Command::Repoinfo(opts) => repoinfo::execute(&dbe, &be_hot, opts)?,
Command::Tag(opts) => tag::execute(&dbe, opts, config_file)?,

View File

@ -11,6 +11,7 @@ use ignore::{DirEntry, WalkBuilder};
use log::*;
use rayon::ThreadPoolBuilder;
use super::rustic_config::RusticConfig;
use super::{bytes, progress_bytes, progress_counter, wait, warm_up, warm_up_command};
use crate::backend::{DecryptReadBackend, FileType, LocalBackend};
use crate::blob::{Node, NodeStreamer, NodeType, Tree};
@ -18,11 +19,14 @@ use crate::commands::helpers::progress_spinner;
use crate::crypto::hash;
use crate::id::Id;
use crate::index::{IndexBackend, IndexedBackend};
use crate::repo::SnapshotFile;
use crate::repo::{SnapshotFile, SnapshotFilter};
#[derive(Parser)]
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
pub(super) struct Opts {
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
filter: SnapshotFilter,
/// Dry-run: don't restore, only show what would be done
#[clap(long, short = 'n')]
dry_run: bool,
@ -57,7 +61,13 @@ pub(super) struct Opts {
dest: String,
}
pub(super) fn execute(be: &(impl DecryptReadBackend + Unpin), opts: Opts) -> Result<()> {
pub(super) fn execute(
be: &(impl DecryptReadBackend + Unpin),
mut opts: Opts,
config_file: RusticConfig,
) -> Result<()> {
config_file.merge_into("snapshot-filter", &mut opts.filter)?;
if let Some(command) = &opts.warm_up_command {
if !command.contains("%id") {
bail!("warm-up command must contain %id!")
@ -66,7 +76,7 @@ pub(super) fn execute(be: &(impl DecryptReadBackend + Unpin), opts: Opts) -> Res
}
let (id, path) = opts.snap.split_once(':').unwrap_or((&opts.snap, ""));
let snap = SnapshotFile::from_str(be, id, |_| true, progress_counter(""))?;
let snap = SnapshotFile::from_str(be, id, |sn| sn.matches(&opts.filter), progress_counter(""))?;
let index = IndexBackend::new(be, progress_counter(""))?;
let tree = Tree::subtree_id(&index, snap.tree, Path::new(path))?;