From f3b0ac58a8da933ee0c07c07f7467380a8cea53d Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 19 Sep 2023 00:49:44 +0200 Subject: [PATCH] chore(docs): update library documentation Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com> --- src/commands.rs | 9 ++++-- src/commands/backup.rs | 17 ++++++++-- src/commands/cat.rs | 5 +-- src/commands/check.rs | 3 +- src/commands/completions.rs | 2 -- src/commands/config.rs | 3 +- src/commands/copy.rs | 5 +-- src/commands/diff.rs | 45 +++++++++++++++++++++++++-- src/commands/dump.rs | 2 -- src/commands/forget.rs | 12 +++++-- src/commands/init.rs | 29 +++++++++++++++-- src/commands/key.rs | 4 +-- src/commands/list.rs | 4 +-- src/commands/ls.rs | 33 +++++++++++++++++--- src/commands/merge.rs | 3 +- src/commands/prune.rs | 9 ++++-- src/commands/repair.rs | 6 ++-- src/commands/repoinfo.rs | 16 ++++++++-- src/commands/restore.rs | 5 +-- src/commands/self_update.rs | 2 -- src/commands/show_config.rs | 2 -- src/commands/snapshots.rs | 5 +-- src/commands/tag.rs | 3 -- src/config.rs | 57 ++++++++++++++++++++++++++++++++-- src/config/progress_options.rs | 9 ++++++ src/filtering.rs | 19 ++++++++++++ src/helpers.rs | 7 +++++ 27 files changed, 260 insertions(+), 56 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index a8920fcfc..07473d352 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -215,10 +215,13 @@ fn open_repository(config: &Arc) -> Result, + /// Ignore save options #[clap(flatten)] #[serde(flatten)] ignore_save_opts: LocalSourceSaveOptions, @@ -63,28 +62,34 @@ pub struct BackupCmd { #[merge(strategy = merge::bool::overwrite_false)] init: bool, + /// Parent processing options #[clap(flatten, next_help_heading = "Options for parent processing")] #[serde(flatten)] parent_opts: ParentOptions, + /// Exclude options #[clap(flatten, next_help_heading = "Exclude options")] #[serde(flatten)] ignore_filter_opts: LocalSourceFilterOptions, + /// Snapshot options #[clap(flatten, next_help_heading = "Snapshot options")] #[serde(flatten)] snap_opts: SnapshotOptions, + /// Key options (when using --init) #[clap(flatten, next_help_heading = "Key options (when using --init)")] #[serde(skip)] #[merge(skip)] key_opts: KeyOptions, + /// Config options (when using --init) #[clap(flatten, next_help_heading = "Config options (when using --init)")] #[serde(skip)] #[merge(skip)] config_opts: ConfigOptions, + /// Backup sources #[clap(skip)] #[merge(strategy = merge_sources)] sources: Vec, @@ -95,7 +100,13 @@ pub struct BackupCmd { source: String, } -// Merge backup sources: If a source is already defined on left, use that. Else add it. +/// Merge backup sources +/// +/// If a source is already defined on left, use that. Else add it. +/// +/// # Arguments +/// +/// * `left` - Vector of backup sources pub(crate) fn merge_sources(left: &mut Vec, mut right: Vec) { left.append(&mut right); left.sort_by(|opt1, opt2| opt1.source.cmp(&opt2.source)); diff --git a/src/commands/cat.rs b/src/commands/cat.rs index 35cc208b5..2a085eedb 100644 --- a/src/commands/cat.rs +++ b/src/commands/cat.rs @@ -1,7 +1,5 @@ //! `cat` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -11,12 +9,15 @@ use anyhow::Result; use rustic_core::repofile::{BlobType, FileType}; /// `cat` subcommand +/// +/// Output the contents of a file or blob #[derive(clap::Parser, Command, Debug)] pub(crate) struct CatCmd { #[clap(subcommand)] cmd: CatSubCmd, } +/// `cat` subcommands #[derive(clap::Subcommand, Debug)] enum CatSubCmd { /// Display a tree blob diff --git a/src/commands/check.rs b/src/commands/check.rs index ac994b2c3..7de32d048 100644 --- a/src/commands/check.rs +++ b/src/commands/check.rs @@ -1,7 +1,5 @@ //! `check` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -11,6 +9,7 @@ use rustic_core::CheckOptions; /// `check` subcommand #[derive(clap::Parser, Command, Debug)] pub(crate) struct CheckCmd { + /// Check options #[clap(flatten)] opts: CheckOptions, } diff --git a/src/commands/completions.rs b/src/commands/completions.rs index bb0e74857..473f57ce5 100644 --- a/src/commands/completions.rs +++ b/src/commands/completions.rs @@ -1,7 +1,5 @@ //! `completions` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use abscissa_core::{Command, Runnable}; use std::io::Write; diff --git a/src/commands/config.rs b/src/commands/config.rs index c561d04ad..bee33aa8e 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -1,7 +1,5 @@ //! `config` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -13,6 +11,7 @@ use rustic_core::ConfigOptions; /// `config` subcommand #[derive(clap::Parser, Command, Debug)] pub(crate) struct ConfigCmd { + /// Config options #[clap(flatten)] config_opts: ConfigOptions, } diff --git a/src/commands/copy.rs b/src/commands/copy.rs index fc6b1fc86..7511738f0 100644 --- a/src/commands/copy.rs +++ b/src/commands/copy.rs @@ -1,7 +1,5 @@ //! `copy` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{ commands::open_repository, helpers::table_with_titles, status_err, Application, RUSTIC_APP, }; @@ -25,12 +23,15 @@ pub(crate) struct CopyCmd { #[clap(long)] init: bool, + /// Key options (when using --init) #[clap(flatten, next_help_heading = "Key options (when using --init)")] key_opts: KeyOptions, } +/// Target repository options #[derive(Default, Clone, Debug, Deserialize, Merge)] pub struct Targets { + /// Target repositories #[merge(strategy = merge::vec::overwrite_empty)] targets: Vec, } diff --git a/src/commands/diff.rs b/src/commands/diff.rs index ff1943882..d6154afc5 100644 --- a/src/commands/diff.rs +++ b/src/commands/diff.rs @@ -1,7 +1,5 @@ //! `diff` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -35,6 +33,7 @@ pub(crate) struct DiffCmd { #[clap(long)] no_content: bool, + /// Ignore options #[clap(flatten)] ignore_opts: LocalSourceFilterOptions, } @@ -122,6 +121,16 @@ impl DiffCmd { } } +/// Split argument into snapshot id and path +/// +/// # Arguments +/// +/// * `arg` - argument to split +/// * `default_path` - default path if no path is given +/// +/// # Returns +/// +/// A tuple of the snapshot id and the path fn arg_to_snap_path<'a>(arg: &'a str, default_path: &'a str) -> (Option<&'a str>, &'a str) { match arg.split_once(':') { Some((id, path)) => (Some(id), path), @@ -135,6 +144,25 @@ fn arg_to_snap_path<'a>(arg: &'a str, default_path: &'a str) -> (Option<&'a str> } } +/// Check if the content of a file in a snapshot is identical to the content of a local file +/// +/// # Arguments +/// +/// * `local` - local destination +/// * `repo` - repository +/// * `path` - path of the file in the snapshot +/// * `node` - node of the file in the snapshot +/// +/// # Errors +/// +/// * [`RepositoryErrorKind::IdNotFound`] - If the id of a blob is not found in the repository +/// +/// # Returns +/// +/// `true` if the content of the file in the snapshot is identical to the content of the local file, +/// `false` otherwise +/// +/// [`RepositoryErrorKind::IdNotFound`]: rustic_core::error::RepositoryErrorKind::IdNotFound fn identical_content_local( local: &LocalDestination, repo: &Repository, @@ -155,6 +183,19 @@ fn identical_content_local( Ok(true) } +/// Compare two streams of nodes and print the differences +/// +/// # Arguments +/// +/// * `tree_streamer1` - first stream of nodes +/// * `tree_streamer2` - second stream of nodes +/// * `no_content` - don't check for different file contents +/// * `file_identical` - function to check if the content of two files is identical +/// * `metadata` - show differences in metadata +/// +/// # Errors +/// +// TODO!: add errors! fn diff( mut tree_streamer1: impl Iterator>, mut tree_streamer2: impl Iterator>, diff --git a/src/commands/dump.rs b/src/commands/dump.rs index f74fa5fc5..a90cc996e 100644 --- a/src/commands/dump.rs +++ b/src/commands/dump.rs @@ -1,7 +1,5 @@ //! `dump` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; diff --git a/src/commands/forget.rs b/src/commands/forget.rs index 86dd94ae0..77eaf2aa1 100644 --- a/src/commands/forget.rs +++ b/src/commands/forget.rs @@ -1,7 +1,5 @@ //! `forget` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{ commands::open_repository, helpers::table_with_titles, status_err, Application, RusticConfig, RUSTIC_APP, @@ -32,9 +30,11 @@ pub(super) struct ForgetCmd { #[clap(long)] json: bool, + /// Forget options #[clap(flatten)] config: ForgetOptions, + /// Prune options (only when used with --prune) #[clap( flatten, next_help_heading = "PRUNE OPTIONS (only when used with --prune)" @@ -57,6 +57,7 @@ impl Override for ForgetCmd { } } +/// Forget options #[serde_as] #[derive(Clone, Default, Debug, clap::Parser, Deserialize, Merge)] #[serde(default, rename_all = "kebab-case")] @@ -71,10 +72,12 @@ pub struct ForgetOptions { #[merge(strategy = merge::bool::overwrite_false)] prune: bool, + /// Snapshot filter options #[clap(flatten, next_help_heading = "Snapshot filter options")] #[serde(flatten)] filter: SnapshotFilter, + /// Retention options #[clap(flatten, next_help_heading = "Retention options")] #[serde(flatten)] keep: KeepOptions, @@ -146,6 +149,11 @@ impl ForgetCmd { } } +/// Print groups to stdout +/// +/// # Arguments +/// +/// * `groups` - forget groups to print fn print_groups(groups: &ForgetGroups) { for ForgetGroup { group, snapshots } in &groups.0 { if !group.is_empty() { diff --git a/src/commands/init.rs b/src/commands/init.rs index 6a42b8275..9df694e76 100644 --- a/src/commands/init.rs +++ b/src/commands/init.rs @@ -1,7 +1,5 @@ //! `init` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use abscissa_core::{status_err, Command, Runnable, Shutdown}; use anyhow::{bail, Result}; @@ -14,9 +12,11 @@ use rustic_core::{ConfigOptions, KeyOptions, OpenStatus, Repository}; /// `init` subcommand #[derive(clap::Parser, Command, Debug)] pub(crate) struct InitCmd { + /// Key options #[clap(flatten, next_help_heading = "Key options")] key_opts: KeyOptions, + /// Config options #[clap(flatten, next_help_heading = "Config options")] config_opts: ConfigOptions, } @@ -48,6 +48,31 @@ impl InitCmd { } } +/// Initialize repository +/// +/// # Arguments +/// +/// * `repo` - Repository to initialize +/// * `key_opts` - Key options +/// * `config_opts` - Config options +/// +/// # Errors +/// +/// * [`RepositoryErrorKind::OpeningPasswordFileFailed`] - If opening the password file failed +/// * [`RepositoryErrorKind::ReadingPasswordFromReaderFailed`] - If reading the password failed +/// * [`RepositoryErrorKind::FromSplitError`] - If splitting the password command failed +/// * [`RepositoryErrorKind::PasswordCommandParsingFailed`] - If parsing the password command failed +/// * [`RepositoryErrorKind::ReadingPasswordFromCommandFailed`] - If reading the password from the command failed +/// +/// # Returns +/// +/// Returns the initialized repository +/// +/// [`RepositoryErrorKind::OpeningPasswordFileFailed`]: rustic_core::error::RepositoryErrorKind::OpeningPasswordFileFailed +/// [`RepositoryErrorKind::ReadingPasswordFromReaderFailed`]: rustic_core::error::RepositoryErrorKind::ReadingPasswordFromReaderFailed +/// [`RepositoryErrorKind::FromSplitError`]: rustic_core::error::RepositoryErrorKind::FromSplitError +/// [`RepositoryErrorKind::PasswordCommandParsingFailed`]: rustic_core::error::RepositoryErrorKind::PasswordCommandParsingFailed +/// [`RepositoryErrorKind::ReadingPasswordFromCommandFailed`]: rustic_core::error::RepositoryErrorKind::ReadingPasswordFromCommandFailed pub(crate) fn init( repo: Repository, key_opts: &KeyOptions, diff --git a/src/commands/key.rs b/src/commands/key.rs index cdd5f7964..f00cede3e 100644 --- a/src/commands/key.rs +++ b/src/commands/key.rs @@ -1,7 +1,5 @@ //! `key` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use std::path::PathBuf; @@ -16,6 +14,7 @@ use rustic_core::{KeyOptions, Repository, RepositoryOptions}; /// `key` subcommand #[derive(clap::Parser, Command, Debug)] pub(super) struct KeyCmd { + /// Subcommand to run #[clap(subcommand)] cmd: KeySubCmd, } @@ -32,6 +31,7 @@ pub(crate) struct AddCmd { #[clap(long)] pub(crate) new_password_file: Option, + /// Key options #[clap(flatten)] pub(crate) key_opts: KeyOptions, } diff --git a/src/commands/list.rs b/src/commands/list.rs index ea167fbe9..4605bd2d9 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -1,7 +1,5 @@ //! `list` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -13,7 +11,7 @@ use rustic_core::repofile::{FileType, IndexFile}; /// `list` subcommand #[derive(clap::Parser, Command, Debug)] pub(crate) struct ListCmd { - /// File type to list + /// File types to list #[clap(value_parser=["blobs", "index", "packs", "snapshots", "keys"])] tpe: String, } diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 4d2048fee..de0f4b4c4 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -2,8 +2,6 @@ use std::path::Path; -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -45,6 +43,7 @@ pub(crate) struct LsCmd { #[clap(long, short = 'l')] long: bool, + /// Listing options #[clap(flatten)] ls_opts: LsOptions, } @@ -58,6 +57,9 @@ impl Runnable for LsCmd { } } +/// Sumary of a ls command +/// +/// This struct is used to print a summary of the ls command. #[derive(Default)] struct Summary { files: usize, @@ -66,6 +68,11 @@ struct Summary { } impl Summary { + /// Update the summary with the node + /// + /// # Arguments + /// + /// * `node` - the node to update the summary with fn update(&mut self, node: &Node) { if node.is_dir() { self.dirs += 1; @@ -113,7 +120,12 @@ impl LsCmd { } } -// print node in format similar to unix `ls` +/// Print node in format similar to unix `ls` +/// +/// # Arguments +/// +/// * `node` - the node to print +/// * `path` - the path of the node fn print_node(node: &Node, path: &Path) { println!( "{:>1}{:>9} {:>8} {:>8} {:>9} {:>12} {path:?} {}", @@ -145,7 +157,7 @@ fn print_node(node: &Node, path: &Path) { ); } -// helper fn to put permissions in readable format +/// Convert permissions into readable format fn parse_permissions(mode: u32) -> String { let user = triplet(mode, S_IRUSR, S_IWUSR, S_IXUSR); let group = triplet(mode, S_IRGRP, S_IWGRP, S_IXGRP); @@ -153,7 +165,18 @@ fn parse_permissions(mode: u32) -> String { [user, group, other].join("") } -// helper fn to put permissions in readable format +/// Create a triplet of permissions +/// +/// # Arguments +/// +/// * `mode` - the mode to convert +/// * `read` - the read bit +/// * `write` - the write bit +/// * `execute` - the execute bit +/// +/// # Returns +/// +/// The triplet of permissions as a string fn triplet(mode: u32, read: u32, write: u32, execute: u32) -> String { match (mode & read, mode & write, mode & execute) { (0, 0, 0) => "---", diff --git a/src/commands/merge.rs b/src/commands/merge.rs index ae7acb367..2ee7415f8 100644 --- a/src/commands/merge.rs +++ b/src/commands/merge.rs @@ -1,7 +1,5 @@ //! `merge` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; use anyhow::Result; @@ -26,6 +24,7 @@ pub(super) struct MergeCmd { #[clap(long)] delete: bool, + /// Snapshot options #[clap(flatten, next_help_heading = "Snapshot options")] snap_opts: SnapshotOptions, } diff --git a/src/commands/prune.rs b/src/commands/prune.rs index d39f58d5d..7e4353974 100644 --- a/src/commands/prune.rs +++ b/src/commands/prune.rs @@ -1,7 +1,5 @@ //! `prune` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{ commands::open_repository, helpers::bytes_size_to_string, status_err, Application, RUSTIC_APP, }; @@ -16,6 +14,7 @@ use rustic_core::{PruneOptions, PruneStats}; #[allow(clippy::struct_excessive_bools)] #[derive(clap::Parser, Command, Debug, Clone)] pub(crate) struct PruneCmd { + /// Prune options #[clap(flatten)] pub(crate) opts: PruneOptions, } @@ -47,6 +46,12 @@ impl PruneCmd { Ok(()) } } + +/// Print statistics about the prune operation +/// +/// # Arguments +/// +/// * `stats` - Statistics about the prune operation #[allow(clippy::cast_precision_loss)] fn print_stats(stats: &PruneStats) { let pack_stat = &stats.packs; diff --git a/src/commands/repair.rs b/src/commands/repair.rs index 6c77c7d5c..265f0207e 100644 --- a/src/commands/repair.rs +++ b/src/commands/repair.rs @@ -1,7 +1,5 @@ //! `repair` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -12,6 +10,7 @@ use rustic_core::{RepairIndexOptions, RepairSnapshotsOptions}; /// `repair` subcommand #[derive(clap::Parser, Command, Debug)] pub(crate) struct RepairCmd { + /// Subcommand to run #[clap(subcommand)] cmd: RepairSubCmd, } @@ -26,12 +25,15 @@ enum RepairSubCmd { #[derive(Default, Debug, clap::Parser, Command)] struct IndexSubCmd { + /// Index repair options #[clap(flatten)] opts: RepairIndexOptions, } +/// `repair snapshots` subcommand #[derive(Default, Debug, clap::Parser, Command)] struct SnapSubCmd { + /// Snapshot repair options #[clap(flatten)] opts: RepairSnapshotsOptions, diff --git a/src/commands/repoinfo.rs b/src/commands/repoinfo.rs index 7d43f55e5..887c42976 100644 --- a/src/commands/repoinfo.rs +++ b/src/commands/repoinfo.rs @@ -1,7 +1,5 @@ //! `repoinfo` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{ commands::open_repository, helpers::bytes_size_to_string, status_err, Application, RUSTIC_APP, }; @@ -38,6 +36,9 @@ impl Runnable for RepoInfoCmd { } } +/// Infos about the repository +/// +/// This struct is used to serialize infos in `json` format. #[serde_with::apply(Option => #[serde(default, skip_serializing_if = "Option::is_none")])] #[derive(Serialize)] struct Infos { @@ -85,6 +86,12 @@ impl RepoInfoCmd { } } +/// Print infos about repository files +/// +/// # Arguments +/// +/// * `text` - the text to print before the table +/// * `info` - the [`RepoFileInfo`]s to print pub fn print_file_info(text: &str, info: Vec) { let mut table = table_right_from(1, ["File type", "Count", "Total Size"]); let mut total_count = 0; @@ -110,6 +117,11 @@ pub fn print_file_info(text: &str, info: Vec) { println!(); } +/// Print infos about index +/// +/// # Arguments +/// +/// * `index_info` - the [`IndexInfos`] to print pub fn print_index_info(index_info: IndexInfos) { let mut table = table_right_from( 1, diff --git a/src/commands/restore.rs b/src/commands/restore.rs index 703fee41b..46a2504d2 100644 --- a/src/commands/restore.rs +++ b/src/commands/restore.rs @@ -1,7 +1,5 @@ //! `restore` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{ commands::open_repository, helpers::bytes_size_to_string, status_err, Application, RUSTIC_APP, }; @@ -26,12 +24,15 @@ pub(crate) struct RestoreCmd { #[clap(value_name = "DESTINATION")] dest: String, + /// Restore options #[clap(flatten)] opts: RestoreOptions, + /// List options #[clap(flatten)] ls_opts: LsOptions, + /// Snapshot filter options (when using latest) #[clap( flatten, next_help_heading = "Snapshot filter options (when using latest)" diff --git a/src/commands/self_update.rs b/src/commands/self_update.rs index e1f5e38d2..a8231a6b5 100644 --- a/src/commands/self_update.rs +++ b/src/commands/self_update.rs @@ -1,7 +1,5 @@ //! `self-update` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{Application, RUSTIC_APP}; use abscissa_core::{status_err, Command, Runnable, Shutdown}; diff --git a/src/commands/show_config.rs b/src/commands/show_config.rs index eea0c1e13..10797fe10 100644 --- a/src/commands/show_config.rs +++ b/src/commands/show_config.rs @@ -1,7 +1,5 @@ //! `show-config` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable}; diff --git a/src/commands/snapshots.rs b/src/commands/snapshots.rs index f7443a967..e91ca9ff7 100644 --- a/src/commands/snapshots.rs +++ b/src/commands/snapshots.rs @@ -1,7 +1,5 @@ //! `smapshot` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{ commands::open_repository, helpers::{bold_cell, bytes_size_to_string, table, table_right_from}, @@ -47,6 +45,7 @@ pub(crate) struct SnapshotCmd { #[clap(long, conflicts_with_all = &["long", "json"])] all: bool, } + impl Runnable for SnapshotCmd { fn run(&self) { if let Err(err) = self.inner_run() { @@ -142,7 +141,9 @@ impl SnapshotCmd { } } +/// Trait to print a table trait PrintTable { + /// Print a table fn print_table(&self); } diff --git a/src/commands/tag.rs b/src/commands/tag.rs index b6df56995..d7855b334 100644 --- a/src/commands/tag.rs +++ b/src/commands/tag.rs @@ -1,7 +1,5 @@ //! `tag` subcommand -/// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` -/// accessors along with logging macros. Customize as you see fit. use crate::{commands::open_repository, status_err, Application, RUSTIC_APP}; use abscissa_core::{Command, Runnable, Shutdown}; @@ -11,7 +9,6 @@ use chrono::{Duration, Local}; use rustic_core::{repofile::DeleteOption, StringList}; /// `tag` subcommand - #[derive(clap::Parser, Command, Debug)] pub(crate) struct TagCmd { /// Snapshots to change tags. If none is given, use filter to filter from all diff --git a/src/config.rs b/src/config.rs index 19a97e268..0aaf8418b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -27,29 +27,47 @@ use crate::{ }; /// Rustic Configuration +/// +/// Further documentation can be found [here](https://github.com/rustic-rs/rustic/blob/main/config/README.md). +/// +/// # Example +// TODO: add example #[derive(Clone, Default, Debug, Parser, Deserialize, Merge)] #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] pub struct RusticConfig { + /// Global options #[clap(flatten, next_help_heading = "Global options")] pub global: GlobalOptions, + /// Repository options #[clap(flatten, next_help_heading = "Repository options")] pub repository: RepositoryOptions, + /// Snapshot filter options #[clap(flatten, next_help_heading = "Snapshot filter options")] pub snapshot_filter: SnapshotFilter, + /// Backup options #[clap(skip)] pub backup: BackupCmd, + /// Copy options #[clap(skip)] pub copy: Targets, + /// Forget options #[clap(skip)] pub forget: ForgetOptions, } impl RusticConfig { + /// Merge a profile into the current config + /// + /// # Arguments + /// + /// * `profile` - name of the profile to merge + /// + // TODO!: Explain more pub fn merge_profile(&mut self, profile: &str) -> Result<(), FrameworkError> { let profile_filename = profile.to_string() + ".toml"; let paths = get_config_paths(&profile_filename); @@ -77,6 +95,9 @@ impl RusticConfig { } } +/// Global options +/// +/// These options are available for all commands. #[derive(Default, Debug, Parser, Clone, Deserialize, Serialize, Merge)] #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] pub struct GlobalOptions { @@ -92,7 +113,7 @@ pub struct GlobalOptions { #[merge(strategy = merge::vec::append)] pub use_profile: Vec, - /// Only show what would be done without modifying anything. Does not affect read-only commands + /// Only show what would be done without modifying anything. Does not affect read-only commands. #[clap(long, short = 'n', global = true, env = "RUSTIC_DRY_RUN")] #[merge(strategy = merge::bool::overwrite_false)] pub dry_run: bool, @@ -102,7 +123,10 @@ pub struct GlobalOptions { pub log_level: Option, /// Write log messages to the given file instead of printing them. - /// Note: warnings and errors are still additionally printed unless they are ignored by --log-level + /// + /// # Note + /// + /// Warnings and errors are still additionally printed unless they are ignored by `--log-level` #[clap(long, global = true, env = "RUSTIC_LOG_FILE", value_name = "LOGFILE")] pub log_file: Option, @@ -117,11 +141,21 @@ pub struct GlobalOptions { pub env: HashMap, } -/// extend the contents of right to left. +/// Extend the contents of a [`HashMap`] with the contents of another +/// [`HashMap`] with the same key and value types. fn extend(left: &mut HashMap, right: HashMap) { left.extend(right); } +/// Get the paths to the config file +/// +/// # Arguments +/// +/// * `filename` - name of the config file +/// +/// # Returns +/// +/// A vector of [`PathBuf`]s to the config files fn get_config_paths(filename: &str) -> Vec { [ ProjectDirs::from("", "", "rustic") @@ -139,6 +173,12 @@ fn get_config_paths(filename: &str) -> Vec { .collect() } +/// Get the path to the global config directory on Windows. +/// +/// # Returns +/// +/// The path to the global config directory on Windows. +/// If the environment variable `PROGRAMDATA` is not set, `None` is returned. #[cfg(target_os = "windows")] fn get_global_config_path() -> Option { std::env::var_os("PROGRAMDATA").map(|program_data| { @@ -148,11 +188,22 @@ fn get_global_config_path() -> Option { }) } +/// Get the path to the global config directory on ios and wasm targets. +/// +/// # Returns +/// +/// `None` is returned. #[cfg(any(target_os = "ios", target_arch = "wasm32"))] fn get_global_config_path() -> Option { None } +/// Get the path to the global config directory on non-Windows, +/// non-iOS, non-wasm targets. +/// +/// # Returns +/// +/// "/etc/rustic" is returned. #[cfg(not(any(target_os = "windows", target_os = "ios", target_arch = "wasm32")))] fn get_global_config_path() -> Option { Some(PathBuf::from("/etc/rustic")) diff --git a/src/config/progress_options.rs b/src/config/progress_options.rs index 4eadcba79..7b325bb84 100644 --- a/src/config/progress_options.rs +++ b/src/config/progress_options.rs @@ -12,6 +12,7 @@ use serde_with::{serde_as, DisplayFromStr}; use rustic_core::{Progress, ProgressBars}; +/// Progress Bar Config #[serde_as] #[derive(Default, Debug, Parser, Clone, Copy, Deserialize, Serialize, Merge)] #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] @@ -34,14 +35,21 @@ pub struct ProgressOptions { } impl ProgressOptions { + /// Get the progress interval + /// + /// # Returns + /// + /// `Duration::ZERO` if no progress is enabled fn progress_interval(&self) -> Duration { self.progress_interval.map_or(Duration::ZERO, |i| *i) } + /// Create a hidden progress bar pub fn no_progress() -> RusticProgress { RusticProgress(ProgressBar::hidden()) } } + impl ProgressBars for ProgressOptions { type P = RusticProgress; @@ -97,6 +105,7 @@ impl ProgressBars for ProgressOptions { } } +/// A default progress bar #[derive(Debug, Clone)] pub struct RusticProgress(ProgressBar); diff --git a/src/filtering.rs b/src/filtering.rs index 9549f4b38..fefb7ae1c 100644 --- a/src/filtering.rs +++ b/src/filtering.rs @@ -8,6 +8,9 @@ use rhai::{serde::to_dynamic, Dynamic, Engine, FnPtr, AST}; use serde::Deserialize; use serde_with::{serde_as, DisplayFromStr}; +/// A function to filter snapshots +/// +/// The function is called with a [`SnapshotFile`] and must return a boolean. #[derive(Clone, Debug)] pub(crate) struct SnapshotFn(FnPtr, AST); @@ -22,6 +25,13 @@ impl FromStr for SnapshotFn { } impl SnapshotFn { + /// Call the function with a [`SnapshotFile`] + /// + /// The function must return a boolean. + /// + /// # Errors + /// + // TODO!: add errors! fn call( &self, sn: &SnapshotFile, @@ -65,6 +75,15 @@ pub struct SnapshotFilter { } impl SnapshotFilter { + /// Check if a [`SnapshotFile`] matches the filter + /// + /// # Arguments + /// + /// * `snapshot` - The snapshot to check + /// + /// # Returns + /// + /// `true` if the snapshot matches the filter, `false` otherwise #[must_use] pub fn matches(&self, snapshot: &SnapshotFile) -> bool { if let Some(filter_fn) = &self.filter_fn { diff --git a/src/helpers.rs b/src/helpers.rs index 34261ac7a..f9b858592 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,10 +5,12 @@ use comfy_table::{ /// Helpers for table output +/// Create a new bold cell pub fn bold_cell(s: T) -> Cell { Cell::new(s).add_attribute(Attribute::Bold) } +/// Create a new table with default settings #[must_use] pub fn table() -> Table { let mut table = Table::new(); @@ -18,12 +20,16 @@ pub fn table() -> Table { table } +/// Create a new table with titles +/// +/// The first row will be bold pub fn table_with_titles, T: ToString>(titles: I) -> Table { let mut table = table(); _ = table.set_header(titles.into_iter().map(bold_cell)); table } +/// Create a new table with titles and right aligned columns pub fn table_right_from, T: ToString>(start: usize, titles: I) -> Table { let mut table = table_with_titles(titles); // set alignment of all rows except first start row @@ -35,6 +41,7 @@ pub fn table_right_from, T: ToString>(start: usize, ti table } +/// Convert a [`ByteSize`] to a human readable string #[must_use] pub fn bytes_size_to_string(b: u64) -> String { ByteSize(b).to_string_as(true)