refactor: exit codes

This commit is contained in:
iff 2024-12-06 19:12:40 +01:00
parent dae09adb76
commit a8561ed488
5 changed files with 91 additions and 70 deletions

View file

@ -1,10 +1,17 @@
use crate::shell::initialization; use crate::shell::initialization;
pub enum Status {
Continue,
Exit, // version, help, etc.
Error,
}
// returns true if should exit // returns true if should exit
pub fn handle_args() -> bool { pub fn handle_args() -> Status {
use Status::*;
let args = std::env::args().collect::<Vec<String>>(); let args = std::env::args().collect::<Vec<String>>();
if args.len() <= 1 { if args.len() <= 1 {
return false; return Continue;
} }
let mut auto_aliasing = String::new(); let mut auto_aliasing = String::new();
let mut shell = String::new(); let mut shell = String::new();
@ -14,11 +21,11 @@ pub fn handle_args() -> bool {
match args[index].as_str() { match args[index].as_str() {
"-h" | "--help" => { "-h" | "--help" => {
print_help(); print_help();
return true; return Exit;
} }
"-v" | "--version" => { "-v" | "--version" => {
print_version(); print_version();
return true; return Exit;
} }
"-a" | "--alias" => { "-a" | "--alias" => {
if args.len() > index + 1 { if args.len() > index + 1 {
@ -46,13 +53,13 @@ pub fn handle_args() -> bool {
if shell.is_empty() { if shell.is_empty() {
eprintln!("{}", t!("no-shell")); eprintln!("{}", t!("no-shell"));
return true; return Error;
} }
let binary_path = &args[0]; let binary_path = &args[0];
initialization(&shell, binary_path, &auto_aliasing, cnf); initialization(&shell, binary_path, &auto_aliasing, cnf);
return true; Exit
} }
fn print_help() { fn print_help() {

View file

@ -37,28 +37,39 @@ mod requests;
extern crate rust_i18n; extern crate rust_i18n;
i18n!("i18n", fallback = "en", minify_key = true); i18n!("i18n", fallback = "en", minify_key = true);
fn main() -> Result<(), std::io::Error>{ fn main() -> Result<(), std::io::Error> {
colored::control::set_override(true); colored::control::set_override(true);
let mut data = { let init = init();
let init = init(); let mut data = if let Err(status) = init {
if init.is_none() { match status {
return Ok(()); args::Status::Exit => {
} else { return Ok(());
init.unwrap() }
args::Status::Error => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Invalid input",
));
}
_ => {
unreachable!()
}
} }
} else {
init.ok().unwrap()
}; };
data.expand_command(); data.expand_command();
use shell::Mode; use shell::Mode;
match data.mode { match data.mode {
Mode::Suggestion => modes::suggestion(&mut data), Mode::Suggestion => modes::suggestion(&mut data),
Mode::CNF => modes::cnf(&mut data), Mode::Cnf => modes::cnf(&mut data),
} }
Ok(()) Ok(())
} }
fn init() -> Option<shell::Data> { fn init() -> Result<shell::Data, args::Status> {
let locale = { let locale = {
let sys_locale = get_locale().unwrap_or("en-US".to_string()); let sys_locale = get_locale().unwrap_or("en-US".to_string());
if sys_locale.len() < 2 { if sys_locale.len() < 2 {
@ -69,9 +80,15 @@ fn init() -> Option<shell::Data> {
}; };
rust_i18n::set_locale(&locale[0..2]); rust_i18n::set_locale(&locale[0..2]);
let exit = args::handle_args(); let status = args::handle_args();
if exit { match status {
return None; args::Status::Exit => {
return Err(status);
}
args::Status::Error => {
return Err(status);
}
_ => {}
} }
#[cfg(feature = "request-ai")] #[cfg(feature = "request-ai")]
@ -81,5 +98,5 @@ fn init() -> Option<shell::Data> {
} }
} }
Some(shell::Data::init()) Ok(shell::Data::init())
} }

View file

@ -12,7 +12,7 @@ pub fn suggestion(data: &mut Data) {
loop { loop {
let suggestion = { let suggestion = {
let command = suggest_command(&data); let command = suggest_command(data);
if command.is_none() { if command.is_none() {
break; break;
}; };
@ -32,13 +32,19 @@ pub fn suggestion(data: &mut Data) {
difference.unwrap() difference.unwrap()
}; };
let execution = let execution = suggestions::confirm_suggestion(data, &highlighted_suggestion);
suggestions::confirm_suggestion(&data, &highlighted_suggestion);
if execution.is_ok() { if execution.is_ok() {
return; return;
} else { } else {
data.update_command(&suggestion); data.update_command(&suggestion);
let msg = Some(execution.err().unwrap().split_whitespace().collect::<Vec<&str>>().join(" ")); let msg = Some(
execution
.err()
.unwrap()
.split_whitespace()
.collect::<Vec<&str>>()
.join(" "),
);
data.update_error(msg); data.update_error(msg);
let retry_message = format!("{}...", t!("retry")); let retry_message = format!("{}...", t!("retry"));
@ -71,7 +77,7 @@ pub fn cnf(data: &mut Data) {
let highlighted_suggestion = let highlighted_suggestion =
highlight_difference(&shell, &suggestion, &last_command).unwrap(); highlight_difference(&shell, &suggestion, &last_command).unwrap();
let _ = suggestions::confirm_suggestion(&data, &highlighted_suggestion); let _ = suggestions::confirm_suggestion(data, &highlighted_suggestion);
} else { } else {
let package_manager = match system::get_package_manager(&shell) { let package_manager = match system::get_package_manager(&shell) {
Some(package_manager) => package_manager, Some(package_manager) => package_manager,
@ -100,7 +106,7 @@ pub fn cnf(data: &mut Data) {
// retry after installing package // retry after installing package
if system::install_package(&shell, &package_manager, &package) { if system::install_package(&shell, &package_manager, &package) {
let _ = suggestions::confirm_suggestion(&data, &last_command); let _ = suggestions::confirm_suggestion(data, &last_command);
} }
} }
} }

View file

@ -1,9 +1,9 @@
use std::process::exit; use std::process::exit;
use std::collections::HashMap;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use std::collections::HashMap;
use regex_lite::Regex; use regex_lite::Regex;
@ -11,7 +11,7 @@ pub const PRIVILEGE_LIST: [&str; 2] = ["sudo", "doas"];
pub enum Mode { pub enum Mode {
Suggestion, Suggestion,
CNF, Cnf,
} }
pub struct Data { pub struct Data {
@ -70,7 +70,7 @@ impl Data {
return; return;
} }
let alias = self.alias.as_ref().unwrap(); let alias = self.alias.as_ref().unwrap();
if let Some(suggest) = expand_alias_multiline(alias, &self.suggest.as_ref().unwrap()) { if let Some(suggest) = expand_alias_multiline(alias, self.suggest.as_ref().unwrap()) {
self.update_suggest(&suggest); self.update_suggest(&suggest);
} }
} }
@ -98,7 +98,7 @@ impl Data {
} }
pub fn update_suggest(&mut self, suggest: &str) { pub fn update_suggest(&mut self, suggest: &str) {
let split = split_command(&suggest); let split = split_command(suggest);
if PRIVILEGE_LIST.contains(&split[0].as_str()) { if PRIVILEGE_LIST.contains(&split[0].as_str()) {
self.suggest = Some(suggest.replacen(&split[0], "", 1)); self.suggest = Some(suggest.replacen(&split[0], "", 1));
self.privilege = Some(split[0].clone()) self.privilege = Some(split[0].clone())
@ -195,13 +195,11 @@ pub fn last_command(shell: &str) -> String {
pub fn run_mode() -> Mode { pub fn run_mode() -> Mode {
match std::env::var("_PR_MODE") { match std::env::var("_PR_MODE") {
Ok(mode) => { Ok(mode) => match mode.as_str() {
match mode.as_str() { "suggestion" => Mode::Suggestion,
"suggestion" => Mode::Suggestion, "cnf" => Mode::Cnf,
"cnf" => Mode::CNF, _ => Mode::Suggestion,
_ => Mode::Suggestion, },
}
}
Err(_) => Mode::Suggestion, Err(_) => Mode::Suggestion,
} }
} }
@ -256,11 +254,8 @@ pub fn expand_alias(map: &HashMap<String, String>, command: &str) -> Option<Stri
} else { } else {
command command
}; };
if let Some(expand) = map.get(command) { map.get(command)
Some(command.replacen(&command, expand, 1)) .map(|expand| command.replacen(command, expand, 1))
} else {
None
}
} }
pub fn expand_alias_multiline(map: &HashMap<String, String>, command: &str) -> Option<String> { pub fn expand_alias_multiline(map: &HashMap<String, String>, command: &str) -> Option<String> {
@ -268,7 +263,7 @@ pub fn expand_alias_multiline(map: &HashMap<String, String>, command: &str) -> O
let mut expanded = String::new(); let mut expanded = String::new();
let mut expansion = false; let mut expansion = false;
for line in lines { for line in lines {
if let Some(expand) = expand_alias(&map, line){ if let Some(expand) = expand_alias(map, line) {
expanded = format!("{}\n{}", expanded, expand); expanded = format!("{}\n{}", expanded, expand);
expansion = true; expansion = true;
} else { } else {

View file

@ -7,7 +7,7 @@ use regex_lite::Regex;
use crate::files::{get_best_match_file, get_path_files}; use crate::files::{get_best_match_file, get_path_files};
use crate::rules::match_pattern; use crate::rules::match_pattern;
use crate::shell::{Data, shell_evaluated_commands}; use crate::shell::{shell_evaluated_commands, Data};
pub fn suggest_command(data: &Data) -> Option<String> { pub fn suggest_command(data: &Data) -> Option<String> {
let shell = &data.shell; let shell = &data.shell;
@ -50,8 +50,8 @@ pub fn suggest_command(data: &Data) -> Option<String> {
// skip for commands with no arguments, // skip for commands with no arguments,
// very likely to be an error showing the usage // very likely to be an error showing the usage
if privilege.is_some() && split_command.len() > 2 || if privilege.is_some() && split_command.len() > 2
privilege.is_none() && split_command.len() > 1 || privilege.is_none() && split_command.len() > 1
{ {
let suggest = ai_suggestion(command, error); let suggest = ai_suggestion(command, error);
if let Some(suggest) = suggest { if let Some(suggest) = suggest {
@ -254,10 +254,10 @@ pub fn confirm_suggestion(data: &Data, highlighted: &str) -> Result<(), String>
let command = &data.suggest.clone().unwrap(); let command = &data.suggest.clone().unwrap();
let now = Instant::now(); let now = Instant::now();
let process = run_suggestion(data, &command); let process = run_suggestion(data, command);
if process.success() { if process.success() {
let cd = shell_evaluated_commands(shell, &command); let cd = shell_evaluated_commands(shell, command);
if let Some(cd) = cd { if let Some(cd) = cd {
println!("{}", cd); println!("{}", cd);
} }
@ -284,28 +284,24 @@ fn run_suggestion(data: &Data, command: &str) -> std::process::ExitStatus {
let shell = &data.shell; let shell = &data.shell;
let privilege = &data.privilege; let privilege = &data.privilege;
match privilege { match privilege {
Some(sudo) => { Some(sudo) => std::process::Command::new(sudo)
std::process::Command::new(sudo) .arg(shell)
.arg(shell) .arg("-c")
.arg("-c") .arg(command)
.arg(command) .stdout(stderr())
.stdout(stderr()) .stderr(Stdio::inherit())
.stderr(Stdio::inherit()) .spawn()
.spawn() .expect("failed to execute process")
.expect("failed to execute process") .wait()
.wait() .unwrap(),
.unwrap() None => std::process::Command::new(shell)
} .arg("-c")
None => { .arg(command)
std::process::Command::new(shell) .stdout(stderr())
.arg("-c") .stderr(Stdio::inherit())
.arg(command) .spawn()
.stdout(stderr()) .expect("failed to execute process")
.stderr(Stdio::inherit()) .wait()
.spawn() .unwrap(),
.expect("failed to execute process")
.wait()
.unwrap()
}
} }
} }