Skip to content

Commit

Permalink
Merge pull request #693 from rustic-rs/noprogress
Browse files Browse the repository at this point in the history
rustic_core: Add NoProgress and NoProgressBars (e.g. for examples)
  • Loading branch information
aawsome authored Jun 20, 2023
2 parents 2e4e18f + 2342c5b commit 5ae52a6
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 58 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/rustic_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ expect-test = "1.4.1"
quickcheck = { workspace = true }
quickcheck_macros = { workspace = true }
pretty_assertions = { workspace = true }
simplelog = { workspace = true }

[profile.dev]
opt-level = 0
Expand Down
18 changes: 18 additions & 0 deletions crates/rustic_core/examples/check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! `check` example
use rustic_core::{CheckOpts, Repository, RepositoryOptions};
use simplelog::{Config, LevelFilter, SimpleLogger};

fn main() {
// Display info logs
let _ = SimpleLogger::init(LevelFilter::Info, Config::default());

// Open repository
let mut repo_opts = RepositoryOptions::default();
repo_opts.repository = Some("/tmp/repo".to_string());
repo_opts.password = Some("test".to_string());
let repo = Repository::new(&repo_opts).unwrap().open().unwrap();

// Check respository with standard options
let opts = CheckOpts::default();
repo.check(opts).unwrap()
}
11 changes: 5 additions & 6 deletions crates/rustic_core/src/commands/cat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,30 @@ use crate::{
Tree,
};

pub fn cat_file(repo: &OpenRepository, tpe: FileType, id: &str) -> RusticResult<Bytes> {
pub fn cat_file<P>(repo: &OpenRepository<P>, tpe: FileType, id: &str) -> RusticResult<Bytes> {
let id = repo.dbe.find_id(tpe, id)?;
let data = repo.dbe.read_encrypted_full(tpe, &id)?;
Ok(data)
}

pub fn cat_blob(repo: &IndexedRepository, tpe: BlobType, id: &str) -> RusticResult<Bytes> {
pub fn cat_blob<P>(repo: &IndexedRepository<P>, tpe: BlobType, id: &str) -> RusticResult<Bytes> {
let id = Id::from_hex(id)?;
let data = repo.index.blob_from_backend(tpe, &id)?;

Ok(data)
}

pub fn cat_tree(
repo: &IndexedRepository,
pub fn cat_tree<P: ProgressBars>(
repo: &IndexedRepository<P>,
snap: &str,
sn_filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
pb: &impl ProgressBars,
) -> RusticResult<Bytes> {
let (id, path) = snap.split_once(':').unwrap_or((snap, ""));
let snap = SnapshotFile::from_str(
&repo.repo.dbe,
id,
sn_filter,
&pb.progress_counter("getting snapshot..."),
&repo.repo.pb.progress_counter("getting snapshot..."),
)?;
let node = Tree::node_from_path(&repo.index, snap.tree, Path::new(path))?;
let id = node
Expand Down
9 changes: 5 additions & 4 deletions crates/rustic_core/src/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,24 @@ use crate::{

/// `check` subcommand
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Default)]
pub struct CheckOpts {
/// Don't verify the data saved in the cache
#[cfg_attr(feature = "clap", clap(long, conflicts_with = "no_cache"))]
trust_cache: bool,
pub trust_cache: bool,

/// Read all data blobs
#[cfg_attr(feature = "clap", clap(long))]
read_data: bool,
pub read_data: bool,
}

impl CheckOpts {
pub fn run(self, repo: &OpenRepository, pb: &impl ProgressBars) -> RusticResult<()> {
pub fn run<P: ProgressBars>(self, repo: &OpenRepository<P>) -> RusticResult<()> {
let be = &repo.dbe;
let cache = &repo.cache;
let hot_be = &repo.be_hot;
let raw_be = &repo.be;
let pb = &repo.pb;
if !self.trust_cache {
if let Some(cache) = &cache {
for file_type in [FileType::Snapshot, FileType::Index] {
Expand Down
2 changes: 1 addition & 1 deletion crates/rustic_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub use crate::{
indexer::Indexer,
IndexBackend, IndexEntry, IndexedBackend, ReadIndex,
},
progress::{Progress, ProgressBars},
progress::{NoProgress, NoProgressBars, Progress, ProgressBars},
repofile::{
configfile::ConfigFile,
indexfile::{IndexBlob, IndexFile, IndexPack},
Expand Down
54 changes: 53 additions & 1 deletion crates/rustic_core/src/progress.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,69 @@
use std::borrow::Cow;

use log::info;

/// Trait to report progress information for any rustic action which supports that.
/// Implement this trait when you want to display this progress to your users.
pub trait Progress: Send + Sync + Clone {
/// Check if progress is hidden
fn is_hidden(&self) -> bool;
/// Set total length for this progress
fn set_length(&self, len: u64);
/// Set title for this progress
fn set_title(&self, title: &'static str);
/// Advance progress by given increment
fn inc(&self, inc: u64);
/// Finish the progress
fn finish(&self);
}

/// Trait to start progress information report progress information for any rustic action which supports that.
/// Implement this trait when you want to display this progress to your users.
pub trait ProgressBars {
type P: Progress;
/// Start a new progress, which is hidden
fn progress_hidden(&self) -> Self::P;
/// Start a new progress spinner. Note that this progress doesn't get a length and is not advanced, only finished.
fn progress_spinner(&self, prefix: impl Into<Cow<'static, str>>) -> Self::P;
/// Start a new progress which counts something
fn progress_counter(&self, prefix: impl Into<Cow<'static, str>>) -> Self::P;
fn progress_hidden(&self) -> Self::P;
/// Start a new progress which counts bytes
fn progress_bytes(&self, prefix: impl Into<Cow<'static, str>>) -> Self::P;
}

#[derive(Clone, Copy, Debug)]
pub struct NoProgress;
impl Progress for NoProgress {
fn is_hidden(&self) -> bool {
true
}
fn set_length(&self, _len: u64) {}
fn set_title(&self, title: &'static str) {
info!("{title}");
}
fn inc(&self, _inc: u64) {}
fn finish(&self) {
info!("finished.");
}
}

#[derive(Clone, Copy, Debug)]
pub struct NoProgressBars;
impl ProgressBars for NoProgressBars {
type P = NoProgress;
fn progress_spinner(&self, prefix: impl Into<Cow<'static, str>>) -> Self::P {
info!("{}", prefix.into());
NoProgress
}
fn progress_counter(&self, prefix: impl Into<Cow<'static, str>>) -> Self::P {
info!("{}", prefix.into());
NoProgress
}
fn progress_hidden(&self) -> Self::P {
NoProgress
}
fn progress_bytes(&self, prefix: impl Into<Cow<'static, str>>) -> Self::P {
info!("{}", prefix.into());
NoProgress
}
}
55 changes: 32 additions & 23 deletions crates/rustic_core/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::{
error::RepositoryErrorKind,
index::IndexEntry,
repofile::{configfile::ConfigFile, indexfile::IndexPack, keyfile::find_key_in_backend},
BlobType, IndexBackend, ProgressBars, RusticResult, SnapshotFile,
BlobType, IndexBackend, NoProgressBars, ProgressBars, RusticResult, SnapshotFile,
};

pub(super) mod constants {
Expand Down Expand Up @@ -79,19 +79,19 @@ pub struct RepositoryOptions {
feature = "clap",
clap(short, long, global = true, alias = "repo", env = "RUSTIC_REPOSITORY")
)]
repository: Option<String>,
pub repository: Option<String>,

/// Repository to use as hot storage
#[cfg_attr(
feature = "clap",
clap(long, global = true, alias = "repository_hot", env = "RUSTIC_REPO_HOT")
)]
repo_hot: Option<String>,
pub repo_hot: Option<String>,

/// Password of the repository - WARNING: Using --password can reveal the password in the process list!
#[cfg_attr(feature = "clap", clap(long, global = true, env = "RUSTIC_PASSWORD"))]
// TODO: use `secrecy` library
password: Option<String>,
pub password: Option<String>,

/// File to read the password from
#[cfg_attr(
Expand All @@ -104,7 +104,7 @@ pub struct RepositoryOptions {
conflicts_with = "password"
)
)]
password_file: Option<PathBuf>,
pub password_file: Option<PathBuf>,

/// Command to read the password from
#[cfg_attr(feature = "clap", clap(
Expand All @@ -113,12 +113,12 @@ pub struct RepositoryOptions {
env = "RUSTIC_PASSWORD_COMMAND",
conflicts_with_all = &["password", "password_file"],
))]
password_command: Option<String>,
pub password_command: Option<String>,

/// Don't use a cache.
#[cfg_attr(feature = "clap", clap(long, global = true, env = "RUSTIC_NO_CACHE"))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
no_cache: bool,
pub no_cache: bool,

/// Use this dir as cache dir instead of the standard cache dir
#[cfg_attr(
Expand All @@ -130,7 +130,7 @@ pub struct RepositoryOptions {
env = "RUSTIC_CACHE_DIR"
)
)]
cache_dir: Option<PathBuf>,
pub cache_dir: Option<PathBuf>,

/// Warm up needed data pack files by only requesting them without processing
#[cfg_attr(feature = "clap", clap(long, global = true))]
Expand All @@ -151,7 +151,7 @@ pub struct RepositoryOptions {

#[cfg_attr(feature = "clap", clap(skip))]
#[cfg_attr(feature = "merge", merge(strategy = overwrite))]
options: HashMap<String, String>,
pub options: HashMap<String, String>,
}

// TODO: Unused function
Expand Down Expand Up @@ -196,15 +196,22 @@ pub(crate) fn read_password_from_reader(file: &mut impl BufRead) -> RusticResult
}

#[derive(Debug)]
pub struct Repository {
pub struct Repository<P> {
name: String,
pub be: HotColdBackend<ChooseBackend>,
pub be_hot: Option<ChooseBackend>,
opts: RepositoryOptions,
pb: P,
}

impl Repository {
impl Repository<NoProgressBars> {
pub fn new(opts: &RepositoryOptions) -> RusticResult<Self> {
Self::new_with_progress(opts, NoProgressBars {})
}
}

impl<P> Repository<P> {
pub fn new_with_progress(opts: &RepositoryOptions, pb: P) -> RusticResult<Self> {
let be = match &opts.repository {
Some(repo) => ChooseBackend::from_url(repo)?,
None => return Err(RepositoryErrorKind::NoRepositoryGiven.into()),
Expand Down Expand Up @@ -238,6 +245,7 @@ impl Repository {
be,
be_hot,
opts: opts.clone(),
pb,
})
}

Expand Down Expand Up @@ -276,7 +284,7 @@ impl Repository {
}
}

pub fn open(self) -> RusticResult<OpenRepository> {
pub fn open(self) -> RusticResult<OpenRepository<P>> {
let config_ids = match self.be.list(FileType::Config) {
Ok(val) => val,
Err(_e) => return Err(RepositoryErrorKind::ListingRepositoryConfigFileFailed.into()),
Expand Down Expand Up @@ -329,6 +337,7 @@ impl Repository {
be_hot: self.be_hot,
config,
opts: self.opts,
pb: self.pb,
})
}
}
Expand Down Expand Up @@ -357,7 +366,7 @@ pub(crate) fn get_key(be: &impl ReadBackend, password: Option<String>) -> Rustic
}

#[derive(Debug)]
pub struct OpenRepository {
pub struct OpenRepository<P> {
pub name: String,
pub be: HotColdBackend<ChooseBackend>,
pub be_hot: Option<ChooseBackend>,
Expand All @@ -366,40 +375,40 @@ pub struct OpenRepository {
pub dbe: DecryptBackend<CachedBackend<HotColdBackend<ChooseBackend>>, Key>,
pub config: ConfigFile,
pub opts: RepositoryOptions,
pub(crate) pb: P,
}

impl OpenRepository {
impl<P: ProgressBars> OpenRepository<P> {
pub fn cat_file(&self, tpe: FileType, id: &str) -> RusticResult<Bytes> {
commands::cat::cat_file(self, tpe, id)
}

pub fn check(&self, opts: CheckOpts, pb: &impl ProgressBars) -> RusticResult<()> {
opts.run(self, pb)
pub fn check(&self, opts: CheckOpts) -> RusticResult<()> {
opts.run(self)
}

pub fn to_indexed(self, pb: &impl ProgressBars) -> RusticResult<IndexedRepository> {
let index = IndexBackend::new(&self.dbe, &pb.progress_counter(""))?;
pub fn to_indexed(self) -> RusticResult<IndexedRepository<P>> {
let index = IndexBackend::new(&self.dbe, &self.pb.progress_counter(""))?;
Ok(IndexedRepository { repo: self, index })
}
}

#[derive(Debug)]
pub struct IndexedRepository {
pub(crate) repo: OpenRepository,
pub struct IndexedRepository<P> {
pub(crate) repo: OpenRepository<P>,
pub(crate) index:
IndexBackend<DecryptBackend<CachedBackend<HotColdBackend<ChooseBackend>>, Key>>,
}

impl IndexedRepository {
impl<P: ProgressBars> IndexedRepository<P> {
pub fn cat_blob(&self, tpe: BlobType, id: &str) -> RusticResult<Bytes> {
commands::cat::cat_blob(self, tpe, id)
}
pub fn cat_tree(
&self,
snap: &str,
sn_filter: impl FnMut(&SnapshotFile) -> bool + Send + Sync,
pb: &impl ProgressBars,
) -> RusticResult<Bytes> {
commands::cat::cat_tree(self, snap, sn_filter, pb)
commands::cat::cat_tree(self, snap, sn_filter)
}
}
9 changes: 5 additions & 4 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::{
repair::RepairCmd, repoinfo::RepoInfoCmd, restore::RestoreCmd, self_update::SelfUpdateCmd,
show_config::ShowConfigCmd, snapshots::SnapshotCmd, tag::TagCmd,
},
config::RusticConfig,
config::{progress_options::ProgressOptions, RusticConfig},
{Application, RUSTIC_APP},
};

Expand Down Expand Up @@ -167,7 +167,7 @@ impl Configurable<RusticConfig> for EntryPoint {
}
}

fn open_repository(repo: Repository) -> OpenRepository {
fn open_repository<P>(repo: Repository<P>) -> OpenRepository<P> {
match repo.open() {
Ok(it) => it,
Err(err) => {
Expand All @@ -177,8 +177,9 @@ fn open_repository(repo: Repository) -> OpenRepository {
}
}

fn get_repository(config: &Arc<RusticConfig>) -> Repository {
match Repository::new(&config.repository) {
fn get_repository(config: &Arc<RusticConfig>) -> Repository<ProgressOptions> {
let po = config.global.progress_options;
match Repository::new_with_progress(&config.repository, po) {
Ok(it) => it,
Err(err) => {
status_err!("{}", err);
Expand Down
Loading

0 comments on commit 5ae52a6

Please sign in to comment.