mod browser;
mod cli;
mod commands;
mod editor;
mod launch;
mod output;
mod picker;
mod qr;
mod session;
mod when;
use anyhow::Result;
use clap::{CommandFactory, Parser};
use cli::{Cli, Command, PluginAction};
use std::process::ExitCode;
const RUN_FAILED: u8 = 125;
fn main() -> ExitCode {
let arguments = Cli::parse();
let runs_a_command = matches!(arguments.command, Some(Command::Run(_)));
match run(arguments) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("error: {error:#}");
if !runs_a_command {
return ExitCode::FAILURE;
}
match error.downcast_ref::<launch::NotStarted>() {
Some(not_started) => ExitCode::from(not_started.status()),
None => ExitCode::from(RUN_FAILED),
}
}
}
}
fn run(arguments: Cli) -> Result<()> {
let password_env = arguments.password_env.as_deref();
let Some(command) = arguments.command else {
let path = session::vault_path(arguments.vault)?;
let password = session::password(password_env)?;
let vault = session::open(&path, &password)?;
return commands::browse(&vault);
};
match command {
Command::Plugin { action } => {
return match action {
PluginAction::List { paths } => commands::plugin_list(paths),
};
}
Command::Completions { shell } => {
let mut command = Cli::command();
let name = command.get_name().to_owned();
clap_complete::generate(shell, &mut command, name, &mut std::io::stdout());
return Ok(());
}
Command::Gen(args) if args.save.is_none() => return commands::generate(None, args),
Command::Init => {
let path = session::vault_path(arguments.vault)?;
return commands::init(&path, password_env);
}
_ => {}
}
let path = session::vault_path(arguments.vault)?;
let password = session::password(password_env)?;
let mut vault = session::open(&path, &password)?;
match command {
Command::Add { kind } => commands::add(&mut vault, kind),
Command::Get(args) => commands::get(&vault, args),
Command::Show { reference } => commands::show(&vault, &reference),
Command::Ls(args) => commands::ls(&vault, args),
Command::Find(args) => commands::find(&vault, args),
Command::Edit(args) => commands::edit(&mut vault, args),
Command::Rm { reference, yes } => commands::rm(&mut vault, &reference, yes),
Command::Extract {
reference,
output,
force,
} => commands::extract(&vault, &reference, output, force),
Command::Tags => commands::tags(&vault),
Command::Gen(args) => commands::generate(Some(&mut vault), args),
Command::Open(args) => commands::open(&vault, args),
Command::Otp(args) => commands::otp(&mut vault, args),
Command::Fill(args) => commands::fill(&vault, args),
Command::Run(args) => match commands::run(vault, args, password_env)? {},
Command::Status => commands::status(&vault),
Command::Export {
output,
i_know_this_writes_plaintext,
force,
} => commands::export(&vault, output, i_know_this_writes_plaintext, force),
Command::Import { input } => commands::import(&mut vault, input),
Command::Merge {
other,
other_password_env,
} => commands::merge(&mut vault, &other, other_password_env.as_deref()),
Command::ChangePassword { new_password_env } => {
commands::change_password(&mut vault, new_password_env.as_deref())
}
Command::Push(args) => commands::push(&mut vault, args),
Command::Pull(args) => commands::pull(&mut vault, args, &password),
Command::Sync(args) => commands::sync(&mut vault, args, &password),
Command::Init | Command::Plugin { .. } | Command::Completions { .. } => unreachable!(),
}
}