Skip to content

Commit

Permalink
repoinfo: Add options --json, --only-files, --only-index
Browse files Browse the repository at this point in the history
  • Loading branch information
aawsome committed Jun 23, 2023
1 parent 7269708 commit 8795c44
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 91 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
23 changes: 15 additions & 8 deletions crates/rustic_core/src/commands/repoinfo.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
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)]
#[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)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct BlobInfo {
pub blob_type: BlobType,
pub count: u64,
Expand All @@ -29,7 +31,8 @@ impl BlobInfo {
}
}

#[derive(Clone, Copy, Debug)]
#[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,
Expand Down Expand Up @@ -102,13 +105,14 @@ pub(crate) fn collect_index_infos<P: ProgressBars>(
Ok(info)
}

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

#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct RepoFileInfo {
pub tpe: FileType,
pub count: u64,
Expand All @@ -132,5 +136,8 @@ pub fn collect_file_infos<P: ProgressBars>(repo: &Repository<P>) -> RusticResult
let files_hot = repo.be_hot.as_ref().map(collect_file_info).transpose()?;
p.finish();

Ok(RepoFileInfos { files, files_hot })
Ok(RepoFileInfos {
repo: files,
repo_hot: files_hot,
})
}
125 changes: 43 additions & 82 deletions src/commands/repoinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,27 @@ use crate::{
};

use abscissa_core::{Command, Runnable, Shutdown};
use serde::Serialize;

use crate::helpers::table_right_from;
use anyhow::Result;
use rustic_core::RepoFileInfo;
use rustic_core::{IndexInfos, RepoFileInfo, RepoFileInfos};

/// `repoinfo` subcommand
#[derive(clap::Parser, Command, Debug)]
pub(crate) struct RepoInfoCmd;
pub(crate) struct RepoInfoCmd {
/// Only scan repository files (doesn't need repository password)
#[clap(long)]
only_files: bool,

/// Only scan index
#[clap(long)]
only_index: bool,

/// Show infos in json format
#[clap(long)]
json: bool,
}

impl Runnable for RepoInfoCmd {
fn run(&self) {
Expand All @@ -25,97 +38,45 @@ impl Runnable for RepoInfoCmd {
}
}

#[serde_with::apply(Option => #[serde(default, skip_serializing_if = "Option::is_none")])]
#[derive(Serialize)]
struct Infos {
files: Option<RepoFileInfos>,
index: Option<IndexInfos>,
}

impl RepoInfoCmd {
fn inner_run(&self) -> Result<()> {
let config = RUSTIC_APP.config();
let repo = get_repository(&config);
let file_info = repo.infos_files()?;
print_file_info("repository files", file_info.files);
if let Some(info) = file_info.files_hot {
print_file_info("hot repository files", info);
}

let repo = repo.open()?;
let index_info = repo.infos_index()?;

let mut table = table_right_from(
1,
["Blob type", "Count", "Total Size", "Total Size in Packs"],
);

let mut total_count = 0;
let mut total_data_size = 0;
let mut total_size = 0;
let infos = Infos {
files: (!self.only_index).then(|| repo.infos_files()).transpose()?,
index: (!self.only_files)
.then(|| -> Result<_> {
let repo = repo.open()?;
let info_index = repo.infos_index()?;
Ok(info_index)
})
.transpose()?,
};

for blobs in &index_info.blobs {
_ = table.add_row([
format!("{:?}", blobs.blob_type),
blobs.count.to_string(),
bytes_size_to_string(blobs.data_size),
bytes_size_to_string(blobs.size),
]);
total_count += blobs.count;
total_data_size += blobs.data_size;
total_size += blobs.size;
}
for blobs in &index_info.blobs_delete {
if blobs.count > 0 {
_ = table.add_row([
format!("{:?} to delete", blobs.blob_type),
blobs.count.to_string(),
bytes_size_to_string(blobs.data_size),
bytes_size_to_string(blobs.size),
]);
total_count += blobs.count;
total_data_size += blobs.data_size;
total_size += blobs.size;
}
if self.json {
let mut stdout = std::io::stdout();
serde_json::to_writer_pretty(&mut stdout, &infos)?;
return Ok(());
}

_ = table.add_row([
"Total".to_string(),
total_count.to_string(),
bytes_size_to_string(total_data_size),
bytes_size_to_string(total_size),
]);

println!();
println!("{table}");

let mut table = table_right_from(
1,
["Blob type", "Pack Count", "Minimum Size", "Maximum Size"],
);

for packs in index_info.packs {
_ = table.add_row([
format!("{:?} packs", packs.blob_type),
packs.count.to_string(),
packs
.min_size
.map_or("-".to_string(), |s| bytes_size_to_string(s)),
packs
.max_size
.map_or("-".to_string(), |s| bytes_size_to_string(s)),
]);
}
for packs in index_info.packs_delete {
if packs.count > 0 {
_ = table.add_row([
format!("{:?} packs to delete", packs.blob_type),
packs.count.to_string(),
packs
.min_size
.map_or("-".to_string(), |s| bytes_size_to_string(s)),
packs
.max_size
.map_or("-".to_string(), |s| bytes_size_to_string(s)),
]);
if let Some(file_info) = infos.files {
print_file_info("repository files", file_info.repo);
if let Some(info) = file_info.repo_hot {
print_file_info("hot repository files", info);
}
}
println!();
println!("{table}");

if let Some(index_info) = infos.index {
print_index_info(index_info);
}
Ok(())
}
}
Expand Down

0 comments on commit 8795c44

Please sign in to comment.