Skip to main content

rustic_rs/commands/
init.rs

1//! `init` subcommand
2
3use abscissa_core::{Command, Runnable, Shutdown, status_err};
4use anyhow::{Result, bail};
5use dialoguer::Password;
6
7use crate::{
8    Application, RUSTIC_APP,
9    repository::{OpenRepo, Repo},
10};
11
12use rustic_core::{ConfigOptions, CredentialOptions, Credentials, KeyOptions};
13
14/// `init` subcommand
15#[derive(clap::Parser, Command, Debug)]
16pub(crate) struct InitCmd {
17    /// Key options
18    #[clap(flatten, next_help_heading = "Key options")]
19    key_opts: KeyOptions,
20
21    /// Config options
22    #[clap(flatten, next_help_heading = "Config options")]
23    config_opts: ConfigOptions,
24}
25
26impl Runnable for InitCmd {
27    fn run(&self) {
28        if let Err(err) = RUSTIC_APP
29            .config()
30            .repository
31            .run(|repo| self.inner_run(repo))
32        {
33            status_err!("{}", err);
34            RUSTIC_APP.shutdown(Shutdown::Crash);
35        };
36    }
37}
38
39impl InitCmd {
40    fn inner_run(&self, repo: Repo) -> Result<()> {
41        let config = RUSTIC_APP.config();
42
43        // Note: This is again checked in init(), however we want to inform
44        // users before they are prompted to enter a password
45        if repo.config_id()?.is_some() {
46            bail!("Config file already exists. Aborting.");
47        }
48
49        // Handle dry-run mode
50        if config.global.dry_run {
51            bail!(
52                "cannot initialize repository {} in dry-run mode!",
53                repo.name
54            );
55        }
56
57        let _ = init(
58            repo,
59            &config.repository.credential_opts,
60            &self.key_opts,
61            &self.config_opts,
62        )?;
63        Ok(())
64    }
65}
66
67/// Initialize repository
68///
69/// # Arguments
70///
71/// * `repo` - Repository to initialize
72/// * `credential_opts` - Credential options
73/// * `key_opts` - Key options (only used when generating a new key)
74/// * `config_opts` - Config options
75///
76/// # Errors
77///
78/// * If getting the credentials from the options fails
79///
80/// # Returns
81///
82/// Returns the initialized repository
83pub(crate) fn init(
84    repo: Repo,
85    credential_opts: &CredentialOptions,
86    key_opts: &KeyOptions,
87    config_opts: &ConfigOptions,
88) -> Result<OpenRepo> {
89    let pass = init_credentials(credential_opts)?;
90    Ok(repo.0.init(&pass, key_opts, config_opts)?)
91}
92
93pub(crate) fn init_credentials(credential_opts: &CredentialOptions) -> Result<Credentials> {
94    let credentials = credential_opts.credentials()?.unwrap_or_else(|| {
95        match Password::new()
96            .with_prompt("enter password for new key")
97            .allow_empty_password(true)
98            .with_confirmation("confirm password", "passwords do not match")
99            .interact()
100        {
101            Ok(pass) => Credentials::Password(pass),
102            Err(err) => {
103                status_err!("{}", err);
104                RUSTIC_APP.shutdown(Shutdown::Crash);
105            }
106        }
107    });
108
109    Ok(credentials)
110}