use std::process::exit;
use anyhow::anyhow;
use console::{style, Style};
use safeshell::{config::Config, dialog, engine, init, Emojis, ShellContext};
mod cmd;
const DEFAULT_ERR_EXIT_CODE: i32 = 1;
pub const BANNER: &str = r#"
____ __ ____ _ _ _
/ ___| __ _ / _| ___ / ___| | |__ ___ | || |
\___ \ / _` || |_ / _ \\___ \ | '_ \ / _ \| || |
___) || (_| || _|| __/ ___) || | | || __/| || |
|____/ \__,_||_| \___||____/ |_| |_| \___||_||_| "#;
fn main() {
let app = cmd::default::command()
.subcommand(cmd::config::command())
.subcommand(cmd::find::command())
.subcommand(cmd::clear::command())
.subcommand(cmd::stash::command());
let matches = app.clone().get_matches();
let env = env_logger::Env::default().filter_or(
"LOG",
matches.value_of("log").unwrap_or(log::Level::Info.as_str()),
);
env_logger::init_from_env(env);
let config = Config::from(matches.value_of("config-dir"));
let shells_context = match init() {
Ok(s) => s,
Err(e) => {
log::error!("{}", e);
exit(1)
}
};
if matches.is_present("init-shell") {
match engine::PatternsEngine::with_config(&config) {
Ok(engine) => {
let emojis = Emojis::default();
if let Ok(shell_commands) =
engine.find_history_commands_from_shell_list(&shells_context)
{
let sensitive_commands = shell_commands.get_commands_with_secrets();
if sensitive_commands.is_empty() {
eprintln!(
"{} Your shell is clean from sensitive data!",
emojis.confetti
);
} else {
eprintln!(
"{} safeshell found {} sensitive commands in your shell history. run \
`safeshell find` to see more information",
emojis.alarm,
style(sensitive_commands.len()).red()
);
}
}
}
Err(e) => {
log::debug!("could not init engine config. err: {}", e);
}
};
exit(0)
}
if !matches.is_present("no_banner") {
println!(
"{}{}",
style(BANNER).magenta(),
style(app.get_version().unwrap_or("")).dim()
);
}
let res = match matches.subcommand() {
None => Err(anyhow!("command not found")),
Some(tup) => match tup {
("config", subcommand_matches) => cmd::config::run(subcommand_matches, &config),
("find", subcommand_matches) => {
cmd::find::run(subcommand_matches, &shells_context, &config)
}
("clear", subcommand_matches) => {
cmd::clear::run(subcommand_matches, &shells_context, &config)
}
("stash", subcommand_matches) => {
cmd::stash::run(subcommand_matches, select_shell(&shells_context))
}
_ => unreachable!(),
},
};
let exit_with = match res {
Ok(cmd) => {
if let Some(message) = cmd.message {
let style = if exitcode::is_success(cmd.code) {
Style::new().green()
} else {
Style::new().red()
};
eprintln!("\r\n{}\r\n", style.apply_to(message));
}
cmd.code
}
Err(e) => {
log::debug!("{:?}", e);
DEFAULT_ERR_EXIT_CODE
}
};
exit(exit_with)
}
fn select_shell(shell_contexts: &Vec<ShellContext>) -> &ShellContext {
if shell_contexts.len() == 1 {
return &shell_contexts[0];
}
let selections = shell_contexts
.iter()
.map(|f| format!("{:?} : {}", f.history.shell, f.history.path))
.collect::<Vec<_>>();
match dialog::select("Pick your shell", &selections) {
Ok(selection) => &shell_contexts[selection],
Err(e) => {
log::debug!("prompter select err: {:?} ", e);
exit(1)
}
}
}