Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustic_core: Add NoProgress and NoProgressBars (e.g. for examples) #693

Merged
merged 3 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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