1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! See [`Command`].

mod backup_restore;
mod cleanup;
mod diff;
mod edit;
mod init;
mod list;
mod status;
mod upgrade;

use std::path::PathBuf;

use clap::Parser;
use thiserror::Error;

pub(crate) use backup_restore::{run_backup, run_restore};
pub(crate) use cleanup::run_cleanup;
pub(crate) use diff::run_diff;
pub(crate) use edit::run_edit;
pub(crate) use init::run_init;
pub(crate) use list::run_list;
pub(crate) use status::run_status;
pub(crate) use upgrade::run_upgrade;

use crate::newtypes::HoardName;
pub use backup_restore::Error as BackupRestoreError;
pub use edit::Error as EditError;

const DEFAULT_CONFIG: &str = include_str!("../../config.toml.sample");

/// Errors that can occur while running commands.
#[derive(Debug, Error)]
pub enum Error {
    /// Error occurred while printing the help message.
    #[error("error while printing help message: {0}")]
    PrintHelp(#[from] clap::Error),
    /// Error occurred while backing up a hoard.
    #[error("failed to back up: {0}")]
    Backup(#[source] BackupRestoreError),
    /// Error occurred while running [`Checkers`](crate::checkers::Checkers).
    #[error("error while running or saving consistency checks: {0}")]
    Checkers(#[from] crate::checkers::Error),
    /// An error occurred while running the cleanup command.
    #[error("error after cleaning up {success_count} log files: {error}")]
    Cleanup {
        /// The number of files successfully cleaned.
        success_count: u32,
        /// The error that occurred.
        #[source]
        error: crate::checkers::history::operation::Error,
    },
    /// Error occurred while running the diff command.
    #[error("error while running hoard diff: {0}")]
    Diff(#[source] crate::hoard::iter::Error),
    /// Error occurred while running the edit command.
    #[error("error while running hoard edit: {0}")]
    Edit(#[from] edit::Error),
    /// Error occurred while initializing Hoard.
    #[error("failed to create {path}: {error}")]
    Init {
        /// The path that could not be created.
        path: PathBuf,
        /// Why that path could not be created.
        #[source]
        error: std::io::Error,
    },
    /// Error occurred while restoring a hoard.
    #[error("failed to restore: {0}")]
    Restore(#[source] backup_restore::Error),
    /// Error occurred while running the status command.
    #[error("error while running hoard status: {0}")]
    Status(#[source] crate::hoard::iter::Error),
    /// Error occurred while upgrading formats.
    #[error("error while running hoard upgrade: {0}")]
    Upgrade(#[from] upgrade::Error),
}

/// The possible subcommands for `hoard`.
#[derive(Clone, PartialEq, Eq, Debug, Parser)]
pub enum Command {
    /// Loads all configuration for validation.
    /// If the configuration loads and builds, this command succeeds.
    Validate,
    /// Cleans up the operation logs for all known systems.
    Cleanup,
    /// Back up the given hoard(s).
    Backup {
        /// The name(s) of the hoard(s) to back up. Will back up all hoards if empty.
        hoards: Vec<HoardName>,
    },
    /// Restore the files from the given hoard to the filesystem.
    Restore {
        /// The name(s) of the hoard(s) to restore. Will restore all hoards if empty.
        hoards: Vec<HoardName>,
    },
    /// List configured hoards.
    List,
    /// Open the configuration file in the system default editor.
    Edit,
    /// Initialize a new Hoard setup.
    Init,
    /// Show which files differ for a given hoard. Optionally show unified diffs for text files
    /// too.
    Diff {
        /// The name of the hoard to diff.
        hoard: HoardName,
        /// If true, prints unified diffs for text files.
        #[clap(long, short)]
        verbose: bool,
    },
    /// Provides a summary of which hoards have changes and if the diffs can be resolved
    /// with a single command.
    Status,
    /// Upgrade internal file formats to the newest format.
    Upgrade,
}

impl Default for Command {
    fn default() -> Self {
        Self::Validate
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn default_command_is_validate() {
        // The default command is validate if one is not given
        assert_eq!(Command::Validate, Command::default());
    }
}