Skip to content

Commit

Permalink
Merge pull request #701 from rustic-rs/refactor-repoinfo
Browse files Browse the repository at this point in the history
Refactor repoinfo
  • Loading branch information
aawsome committed Jun 23, 2023
2 parents f420717 + 8795c44 commit e3bb270
Show file tree
Hide file tree
Showing 8 changed files with 311 additions and 160 deletions.
1 change: 1 addition & 0 deletions changelog/new.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ New features:
- restore: Files are now allocated just before being first processed. This allows easier resumed restores.
- New option: `no-require-git` for backup - if enabled, a git repository is not required to apply `git-ignore` rule.
- fix: wait for password-command to successfully exit, allowing to input something into the command, and read password from stdout.
- repoinfo: Added new options --json, --only-files, --only-index
8 changes: 7 additions & 1 deletion crates/rustic_core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::{io::Read, path::PathBuf};
use bytes::Bytes;
use displaydoc::Display;
use log::trace;
use serde::{Deserialize, Serialize};

use crate::{backend::node::Node, error::BackendErrorKind, id::Id, RusticResult};

Expand All @@ -27,17 +28,22 @@ pub const ALL_FILE_TYPES: [FileType; 4] = [
];

/// Type for describing the kind of a file that can occur.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Display)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Display, Serialize, Deserialize)]
pub enum FileType {
/// config
#[serde(rename = "config")]
Config,
/// index
#[serde(rename = "index")]
Index,
/// keys
#[serde(rename = "key")]
Key,
/// snapshots
#[serde(rename = "snapshot")]
Snapshot,
/// data
#[serde(rename = "pack")]
Pack,
}

Expand Down
1 change: 1 addition & 0 deletions crates/rustic_core/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod cat;
pub mod check;
pub mod repoinfo;
143 changes: 143 additions & 0 deletions crates/rustic_core/src/commands/repoinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use serde::{Deserialize, Serialize};

use crate::{
index::IndexEntry,
repofile::indexfile::{IndexFile, IndexPack},
BlobType, BlobTypeMap, DecryptReadBackend, FileType, OpenRepository, Progress, ProgressBars,
ReadBackend, Repository, RusticResult, ALL_FILE_TYPES,
};

#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct IndexInfos {
pub blobs: Vec<BlobInfo>,
pub blobs_delete: Vec<BlobInfo>,
pub packs: Vec<PackInfo>,
pub packs_delete: Vec<PackInfo>,
}

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct BlobInfo {
pub blob_type: BlobType,
pub count: u64,
pub size: u64,
pub data_size: u64,
}

impl BlobInfo {
pub fn add(&mut self, ie: IndexEntry) {
self.count += 1;
self.size += u64::from(ie.length);
self.data_size += u64::from(ie.data_length());
}
}

#[serde_with::apply(Option => #[serde(default, skip_serializing_if = "Option::is_none")])]
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct PackInfo {
pub blob_type: BlobType,
pub count: u64,
pub min_size: Option<u64>,
pub max_size: Option<u64>,
}

impl PackInfo {
pub fn add(&mut self, ip: &IndexPack) {
self.count += 1;
let size = u64::from(ip.pack_size());
self.min_size = self
.min_size
.map_or(Some(size), |min_size| Some(min_size.min(size)));
self.max_size = self
.max_size
.map_or(Some(size), |max_size| Some(max_size.max(size)));
}
}

pub(crate) fn collect_index_infos<P: ProgressBars>(
repo: &OpenRepository<P>,
) -> RusticResult<IndexInfos> {
let mut blob_info = BlobTypeMap::<()>::default().map(|blob_type, _| BlobInfo {
blob_type,
count: 0,
size: 0,
data_size: 0,
});
let mut blob_info_delete = blob_info;
let mut pack_info = BlobTypeMap::<()>::default().map(|blob_type, _| PackInfo {
blob_type,
count: 0,
min_size: None,
max_size: None,
});
let mut pack_info_delete = pack_info;

let p = repo.pb.progress_counter("scanning index...");
for index in repo.dbe.stream_all::<IndexFile>(&p)? {
let index = index?.1;
for pack in &index.packs {
let tpe = pack.blob_type();
pack_info[tpe].add(pack);

for blob in &pack.blobs {
let ie = IndexEntry::from_index_blob(blob, pack.id);
blob_info[tpe].add(ie);
}
}

for pack in &index.packs_to_delete {
let tpe = pack.blob_type();
pack_info_delete[tpe].add(pack);
for blob in &pack.blobs {
let ie = IndexEntry::from_index_blob(blob, pack.id);
blob_info_delete[tpe].add(ie);
}
}
}
p.finish();

let info = IndexInfos {
blobs: blob_info.into_values().collect(),
blobs_delete: blob_info_delete.into_values().collect(),
packs: pack_info.into_values().collect(),
packs_delete: pack_info_delete.into_values().collect(),
};

Ok(info)
}

#[serde_with::apply(Option => #[serde(default, skip_serializing_if = "Option::is_none")])]
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct RepoFileInfos {
pub repo: Vec<RepoFileInfo>,
pub repo_hot: Option<Vec<RepoFileInfo>>,
}

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct RepoFileInfo {
pub tpe: FileType,
pub count: u64,
pub size: u64,
}

pub(crate) fn collect_file_info(be: &impl ReadBackend) -> RusticResult<Vec<RepoFileInfo>> {
let mut files = Vec::with_capacity(ALL_FILE_TYPES.len());
for tpe in ALL_FILE_TYPES {
let list = be.list_with_size(tpe)?;
let count = list.len() as u64;
let size = list.iter().map(|f| u64::from(f.1)).sum();
files.push(RepoFileInfo { tpe, count, size });
}
Ok(files)
}

pub fn collect_file_infos<P: ProgressBars>(repo: &Repository<P>) -> RusticResult<RepoFileInfos> {
let p = repo.pb.progress_spinner("scanning files...");
let files = collect_file_info(&repo.be)?;
let files_hot = repo.be_hot.as_ref().map(collect_file_info).transpose()?;
p.finish();

Ok(RepoFileInfos {
repo: files,
repo_hot: files_hot,
})
}
7 changes: 5 additions & 2 deletions crates/rustic_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ pub use crate::{
BlobLocation, BlobType, BlobTypeMap, Initialize, Sum,
},
chunker::random_poly,
commands::check::CheckOpts,
commands::{
check::CheckOpts,
repoinfo::{BlobInfo, IndexInfos, PackInfo, RepoFileInfo, RepoFileInfos},
},
crypto::{aespoly1305::Key, hasher::hash},
error::{RusticError, RusticResult},
file::{AddFileResult, FileInfos, RestoreStats},
Expand All @@ -142,5 +145,5 @@ pub use crate::{
},
RepoFile,
},
repository::{parse_command, OpenRepository, RepoInfo, Repository, RepositoryOptions},
repository::{parse_command, OpenRepository, Repository, RepositoryOptions},
};
49 changes: 17 additions & 32 deletions crates/rustic_core/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
};

use bytes::Bytes;
use derive_more::Add;
use log::{debug, error, info};

use nom::{
Expand All @@ -29,45 +28,21 @@ use crate::{
decrypt::DecryptReadBackend, decrypt::DecryptWriteBackend, hotcold::HotColdBackend,
FileType, ReadBackend,
},
commands::{self, check::CheckOpts},
commands::{
self,
check::CheckOpts,
repoinfo::{IndexInfos, RepoFileInfos},
},
crypto::aespoly1305::Key,
error::RepositoryErrorKind,
index::IndexEntry,
repofile::{configfile::ConfigFile, indexfile::IndexPack, keyfile::find_key_in_backend},
repofile::{configfile::ConfigFile, keyfile::find_key_in_backend},
BlobType, IndexBackend, NoProgressBars, ProgressBars, RusticResult, SnapshotFile,
};

pub(super) mod constants {
pub(super) const MAX_PASSWORD_RETRIES: usize = 5;
}

#[derive(Default, Clone, Copy, Add, Debug)]
pub struct RepoInfo {
pub count: u64,
pub size: u64,
pub data_size: u64,
pub pack_count: u64,
pub total_pack_size: u64,
pub min_pack_size: u64,
pub max_pack_size: u64,
}

impl RepoInfo {
pub fn add(&mut self, ie: IndexEntry) {
self.count += 1;
self.size += u64::from(ie.length);
self.data_size += u64::from(ie.data_length());
}

pub fn add_pack(&mut self, ip: &IndexPack) {
self.pack_count += 1;
let size = u64::from(ip.pack_size());
self.total_pack_size += size;
self.min_pack_size = self.min_pack_size.min(size);
self.max_pack_size = self.max_pack_size.max(size);
}
}

#[serde_as]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "merge", derive(merge::Merge))]
Expand Down Expand Up @@ -201,7 +176,7 @@ pub struct Repository<P> {
pub be: HotColdBackend<ChooseBackend>,
pub be_hot: Option<ChooseBackend>,
opts: RepositoryOptions,
pb: P,
pub(crate) pb: P,
}

impl Repository<NoProgressBars> {
Expand Down Expand Up @@ -354,6 +329,12 @@ impl<P> Repository<P> {
}
}

impl<P: ProgressBars> Repository<P> {
pub fn infos_files(&self) -> RusticResult<RepoFileInfos> {
commands::repoinfo::collect_file_infos(self)
}
}

pub(crate) fn get_key(be: &impl ReadBackend, password: Option<String>) -> RusticResult<Key> {
for _ in 0..constants::MAX_PASSWORD_RETRIES {
match password {
Expand Down Expand Up @@ -403,6 +384,10 @@ impl<P: ProgressBars> OpenRepository<P> {
let index = IndexBackend::new(&self.dbe, &self.pb.progress_counter(""))?;
Ok(IndexedRepository { repo: self, index })
}

pub fn infos_index(&self) -> RusticResult<IndexInfos> {
commands::repoinfo::collect_index_infos(self)
}
}

#[derive(Debug)]
Expand Down
Loading

0 comments on commit e3bb270

Please sign in to comment.