Skip to main content

rustic_rs/commands/
repoinfo.rs

1//! `repoinfo` subcommand
2
3use crate::{
4    Application, RUSTIC_APP,
5    helpers::{bytes_size_to_string, table_right_from},
6    repository::Repo,
7    status_err,
8};
9
10use abscissa_core::{Command, Runnable, Shutdown};
11use serde::Serialize;
12
13use anyhow::Result;
14use rustic_core::{IndexInfos, RepoFileInfo, RepoFileInfos};
15
16/// `repoinfo` subcommand
17#[derive(clap::Parser, Command, Debug)]
18pub(crate) struct RepoInfoCmd {
19    /// Only scan repository files (doesn't need credentials)
20    #[clap(long)]
21    only_files: bool,
22
23    /// Only scan index
24    #[clap(long)]
25    only_index: bool,
26
27    /// Show infos in json format
28    #[clap(long)]
29    json: bool,
30}
31
32impl Runnable for RepoInfoCmd {
33    fn run(&self) {
34        if let Err(err) = RUSTIC_APP
35            .config()
36            .repository
37            .run(|repo| self.inner_run(repo))
38        {
39            status_err!("{}", err);
40            RUSTIC_APP.shutdown(Shutdown::Crash);
41        };
42    }
43}
44
45/// Infos about the repository
46///
47/// This struct is used to serialize infos in `json` format.
48#[serde_with::apply(Option => #[serde(default, skip_serializing_if = "Option::is_none")])]
49#[derive(Serialize)]
50struct Infos {
51    files: Option<RepoFileInfos>,
52    index: Option<IndexInfos>,
53}
54
55impl RepoInfoCmd {
56    fn inner_run(&self, repo: Repo) -> Result<()> {
57        let config = RUSTIC_APP.config();
58        let infos = Infos {
59            files: (!self.only_index)
60                .then(|| -> Result<_> { Ok(repo.infos_files()?) })
61                .transpose()?,
62            index: (!self.only_files)
63                .then(|| -> Result<_> {
64                    Ok(repo
65                        .open(&config.repository.credential_opts)?
66                        .infos_index()?)
67                })
68                .transpose()?,
69        };
70
71        if self.json {
72            let mut stdout = std::io::stdout();
73            serde_json::to_writer_pretty(&mut stdout, &infos)?;
74            return Ok(());
75        }
76
77        if let Some(file_info) = infos.files {
78            print_file_info("repository files", file_info.repo);
79            if let Some(info) = file_info.repo_hot {
80                print_file_info("hot repository files", info);
81            }
82        }
83
84        if let Some(index_info) = infos.index {
85            print_index_info(index_info);
86        }
87        Ok(())
88    }
89}
90
91/// Print infos about repository files
92///
93/// # Arguments
94///
95/// * `text` - the text to print before the table
96/// * `info` - the [`RepoFileInfo`]s to print
97pub fn print_file_info(text: &str, info: Vec<RepoFileInfo>) {
98    let mut table = table_right_from(1, ["File type", "Count", "Total Size"]);
99    let mut total_count = 0;
100    let mut total_size = 0;
101    for row in info {
102        _ = table.add_row([
103            format!("{:?}", row.tpe),
104            row.count.to_string(),
105            bytes_size_to_string(row.size),
106        ]);
107        total_count += row.count;
108        total_size += row.size;
109    }
110    println!("{text}");
111    _ = table.add_row([
112        "Total".to_string(),
113        total_count.to_string(),
114        bytes_size_to_string(total_size),
115    ]);
116
117    println!();
118    println!("{table}");
119    println!();
120}
121
122/// Print infos about index
123///
124/// # Arguments
125///
126/// * `index_info` - the [`IndexInfos`] to print
127pub fn print_index_info(index_info: IndexInfos) {
128    let mut table = table_right_from(
129        1,
130        ["Blob type", "Count", "Total Size", "Total Size in Packs"],
131    );
132
133    let mut total_count = 0;
134    let mut total_data_size = 0;
135    let mut total_size = 0;
136
137    for blobs in &index_info.blobs {
138        _ = table.add_row([
139            format!("{:?}", blobs.blob_type),
140            blobs.count.to_string(),
141            bytes_size_to_string(blobs.data_size),
142            bytes_size_to_string(blobs.size),
143        ]);
144        total_count += blobs.count;
145        total_data_size += blobs.data_size;
146        total_size += blobs.size;
147    }
148    for blobs in &index_info.blobs_delete {
149        if blobs.count > 0 {
150            _ = table.add_row([
151                format!("{:?} to delete", blobs.blob_type),
152                blobs.count.to_string(),
153                bytes_size_to_string(blobs.data_size),
154                bytes_size_to_string(blobs.size),
155            ]);
156            total_count += blobs.count;
157            total_data_size += blobs.data_size;
158            total_size += blobs.size;
159        }
160    }
161
162    _ = table.add_row([
163        "Total".to_string(),
164        total_count.to_string(),
165        bytes_size_to_string(total_data_size),
166        bytes_size_to_string(total_size),
167    ]);
168
169    println!();
170    println!("{table}");
171
172    let mut table = table_right_from(
173        1,
174        ["Blob type", "Pack Count", "Minimum Size", "Maximum Size"],
175    );
176
177    for packs in index_info.packs {
178        _ = table.add_row([
179            format!("{:?} packs", packs.blob_type),
180            packs.count.to_string(),
181            packs
182                .min_size
183                .map_or_else(|| "-".to_string(), bytes_size_to_string),
184            packs
185                .max_size
186                .map_or_else(|| "-".to_string(), bytes_size_to_string),
187        ]);
188    }
189    for packs in index_info.packs_delete {
190        if packs.count > 0 {
191            _ = table.add_row([
192                format!("{:?} packs to delete", packs.blob_type),
193                packs.count.to_string(),
194                packs
195                    .min_size
196                    .map_or_else(|| "-".to_string(), bytes_size_to_string),
197                packs
198                    .max_size
199                    .map_or_else(|| "-".to_string(), bytes_size_to_string),
200            ]);
201        }
202    }
203    println!();
204    println!("{table}");
205}