pub mod age;
pub mod cli;
pub mod commands;
pub mod config;
pub mod enclave;
pub mod error;
pub mod git;
pub mod help;
pub mod keystore;
pub mod sops;
pub mod ui;
use clap::Parser;
use crate::cli::{Cli, Command, SecretsCommand};
use crate::error::Result;
use crate::ui::Ui;
pub fn run() -> Result<()> {
let cli = match Cli::try_parse() {
Ok(cli) => cli,
Err(err) => return handle_parse_error(err),
};
let ui = Ui::new(
cli.global.resolve_color(),
cli.global.verbose,
cli.global.resolve_interactive(),
)
.with_git(cli.global.git);
dispatch(&ui, cli.command)
}
fn handle_parse_error(err: clap::Error) -> Result<()> {
use clap::error::ErrorKind;
match err.kind() {
ErrorKind::DisplayHelp => {
print!("{}", help::render(&err.to_string(), help::color_wanted()));
Ok(())
}
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand => {
eprint!("{}", help::render(&err.to_string(), help::color_wanted()));
std::process::exit(2);
}
_ => err.exit(),
}
}
fn dispatch(ui: &Ui, command: Command) -> Result<()> {
match command {
Command::Init(args) => commands::init::run(ui, &args),
Command::Doctor => commands::doctor::run(ui),
Command::Edit(args) => commands::edit::run(ui, &args),
Command::Join(args) => commands::join::run(ui, &args),
Command::Approve(args) => commands::approve::run(ui, &args),
Command::Recipient(cmd) => commands::recipient::run(ui, &cmd),
Command::Secrets(cmd) => commands::secrets::run(ui, &cmd),
Command::Encrypt(args) => commands::secrets::run(ui, &SecretsCommand::Encrypt(args)),
Command::Decrypt(args) => commands::secrets::run(ui, &SecretsCommand::Decrypt(args)),
Command::ListSupportedTypes => {
commands::secrets::list_supported_types(ui);
Ok(())
}
Command::Check => commands::check::run(ui),
Command::Deps(args) => commands::deps::run(ui, &args),
Command::Completion(args) => commands::completion::run(&args),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{CompletionArgs, DepsArgs, InitArgs, SecretsDecryptArgs, SecretsEncryptArgs};
fn test_ui() -> Ui {
Ui::new(false, false, false)
}
#[test]
fn dispatch_doctor_is_ok() {
assert!(dispatch(&test_ui(), Command::Doctor).is_ok());
}
#[test]
fn dispatch_deps_and_completion_are_ok() {
let ui = test_ui();
assert!(
dispatch(
&ui,
Command::Deps(DepsArgs {
check: false,
dry_run: true,
})
)
.is_ok()
);
assert!(
dispatch(
&ui,
Command::Completion(CompletionArgs {
shell: clap_complete::Shell::Bash,
})
)
.is_ok()
);
}
#[test]
fn dispatch_encrypt_decrypt_shorthands_route_to_secrets() {
let ui = test_ui();
assert!(
dispatch(
&ui,
Command::Encrypt(SecretsEncryptArgs {
file: "no-such-file.env".into(),
output: None,
file_type: None,
})
)
.is_err()
);
assert!(
dispatch(
&ui,
Command::Decrypt(SecretsDecryptArgs {
file: "no-such-file.env.encrypted".into(),
output: None,
file_type: None,
})
)
.is_err()
);
}
#[test]
fn dispatch_stub_commands_are_ok() {
let ui = test_ui();
assert!(dispatch(&ui, Command::Check).is_ok());
assert!(
dispatch(
&ui,
Command::Init(InitArgs {
recipient_name: None,
username: None,
public_key: None,
no_generate: true,
break_glass: false,
no_break_glass: true,
force: false,
})
)
.is_err()
);
}
}