From 8c12e4c6c4307dd21749d66680f400067c08a878 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Mon, 18 Apr 2022 10:59:33 +0200 Subject: [PATCH 1/7] Add sudoloop feature that starts a second thread to loop sudo Signed-off-by: Trivernis --- src/args.rs | 8 ++++++-- src/internal/commands.rs | 4 ++++ src/internal/mod.rs | 2 ++ src/internal/sudoloop.rs | 16 ++++++++++++++++ src/main.rs | 6 +++++- src/operations/aur_install.rs | 2 +- 6 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/internal/sudoloop.rs diff --git a/src/args.rs b/src/args.rs index 0f9ea84..0fba04e 100644 --- a/src/args.rs +++ b/src/args.rs @@ -13,6 +13,10 @@ pub struct Args { /// Complete operation without prompting user #[clap(long = "noconfirm")] pub no_confirm: bool, + + /// Loops sudo in the background to ensure it doesn't time out during long builds + #[clap(long = "sudoloop")] + pub sudoloop: bool, } #[derive(Debug, Clone, Subcommand)] @@ -76,10 +80,10 @@ pub struct SearchArgs { #[derive(Default, Debug, Clone, Parser)] pub struct QueryArgs { /// Lists AUR/foreign packages - #[clap(long, short)] + #[clap(long, short, from_global)] pub aur: bool, /// Lists repo/native packages - #[clap(long, short)] + #[clap(long, short, from_global)] pub repo: bool, } diff --git a/src/internal/commands.rs b/src/internal/commands.rs index 6020912..293b842 100644 --- a/src/internal/commands.rs +++ b/src/internal/commands.rs @@ -40,6 +40,10 @@ impl ShellCommand { Self::new("bash") } + pub fn sudo() -> Self { + Self::new("sudo") + } + fn new(command: S) -> Self { Self { command: command.to_string(), diff --git a/src/internal/mod.rs b/src/internal/mod.rs index 5f8be49..fdfd49b 100644 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -7,12 +7,14 @@ pub mod rpc; mod sort; mod strings; pub mod structs; +mod sudoloop; pub use clean::*; pub use initialise::*; pub use sort::*; use std::env; pub use strings::*; +pub use sudoloop::*; #[macro_export] macro_rules! uwu { diff --git a/src/internal/sudoloop.rs b/src/internal/sudoloop.rs new file mode 100644 index 0000000..d2cddfc --- /dev/null +++ b/src/internal/sudoloop.rs @@ -0,0 +1,16 @@ +use crate::ShellCommand; +use std::thread; +use std::time::Duration; + +/// Loop sudo so it doesn't time out +pub fn start_sudoloop() { + prompt_sudo(); + std::thread::spawn(|| loop { + prompt_sudo(); + thread::sleep(Duration::from_secs(3 * 60)) + }); +} + +fn prompt_sudo() { + while let Err(_) = ShellCommand::sudo().arg("-v").wait_success() {} +} diff --git a/src/main.rs b/src/main.rs index a9742b5..e14263a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use internal::commands::ShellCommand; use internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; -use crate::internal::{crash, info, init, log, sort, structs::Options}; +use crate::internal::{crash, info, init, log, sort, start_sudoloop, structs::Options}; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -34,6 +34,10 @@ fn main() { init(options); + if args.sudoloop { + start_sudoloop(); + } + match args.subcommand.unwrap_or_default() { Operation::Install(install_args) => cmd_install(install_args, options), Operation::Remove(remove_args) => cmd_remove(remove_args, options), diff --git a/src/operations/aur_install.rs b/src/operations/aur_install.rs index 9d1be84..054bcfb 100644 --- a/src/operations/aur_install.rs +++ b/src/operations/aur_install.rs @@ -148,7 +148,7 @@ pub fn aur_install(a: Vec, options: Options) { crate::operations::aur_install(md_sorted.aur, newopts); } - let mut makepkg_args = vec!["-rsic", "--skippgp"]; + let mut makepkg_args = vec!["-rsci", "--skippgp"]; if options.asdeps { makepkg_args.push("--asdeps") } From c4d86ca17811f8a7a40c1fd8db023cfdd8677a17 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Mon, 18 Apr 2022 12:43:02 +0200 Subject: [PATCH 2/7] Fix style issue in sudoloop function Signed-off-by: Trivernis --- src/internal/sudoloop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/sudoloop.rs b/src/internal/sudoloop.rs index d2cddfc..a4f6b3a 100644 --- a/src/internal/sudoloop.rs +++ b/src/internal/sudoloop.rs @@ -12,5 +12,5 @@ pub fn start_sudoloop() { } fn prompt_sudo() { - while let Err(_) = ShellCommand::sudo().arg("-v").wait_success() {} + while ShellCommand::sudo().arg("-v").wait_success().is_err() {} } From 2914446be67998a1b350b96e4055e01a5ff7d72a Mon Sep 17 00:00:00 2001 From: trivernis Date: Tue, 5 Jul 2022 20:22:40 +0200 Subject: [PATCH 3/7] Replace logging and output functions with macros Signed-off-by: trivernis --- Cargo.lock | 12 ++++ Cargo.toml | 1 + src/database/add.rs | 23 +++---- src/database/initialise.rs | 9 +-- src/database/mod.rs | 9 +++ src/database/query.rs | 8 +-- src/database/remove.rs | 15 ++--- src/internal/clean.rs | 5 +- src/internal/detect.rs | 9 --- src/internal/error.rs | 4 +- src/internal/initialise.rs | 62 +++++++++--------- src/internal/mod.rs | 5 +- src/internal/sort.rs | 11 ++-- src/internal/strings.rs | 66 ------------------- src/internal/utils.rs | 120 ++++++++++++++++++++++++++++++++++ src/main.rs | 20 +++--- src/operations/aur_install.rs | 70 +++++++++----------- src/operations/install.rs | 20 ++---- src/operations/search.rs | 9 +-- src/operations/uninstall.rs | 9 +-- src/operations/upgrade.rs | 8 +-- 21 files changed, 264 insertions(+), 231 deletions(-) delete mode 100644 src/internal/detect.rs delete mode 100644 src/internal/strings.rs create mode 100644 src/internal/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 38d087d..ebc216b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ name = "Amethyst" version = "3.2.0" dependencies = [ "clap", + "colored", "libc", "mimalloc", "native-tls", @@ -114,6 +115,17 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + [[package]] name = "core-foundation" version = "0.9.3" diff --git a/Cargo.toml b/Cargo.toml index 53dc266..fb11ca9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,3 +58,4 @@ ureq = { version = "2.4.0", default-features = false, features = ["native-tls", serde = { version = "1.0.90", default-features = false, features = ["derive", "serde_derive"] } native-tls = "0.2.8" libc = "0.2.123" +colored = "2.0.0" diff --git a/src/database/add.rs b/src/database/add.rs index 07cbd9a..ebcbf70 100644 --- a/src/database/add.rs +++ b/src/database/add.rs @@ -1,26 +1,21 @@ -use std::env; -use std::path::Path; - -use rusqlite::Connection; - use crate::internal::exit_code::AppExitCode; use crate::internal::rpc::Package; use crate::{crash, log, Options}; +use super::get_database_connection; + pub fn add(pkg: Package, options: Options) { - let conn = Connection::open(Path::new(&format!( - "{}/.local/share/ame/db.sqlite", - env::var("HOME").unwrap() - ))) - .expect("Couldn't connect to database"); + let conn = get_database_connection(); if options.verbosity >= 1 { - log(format!("Adding package {} to database", pkg.name)); + log!("Adding package {} to database", pkg.name); } - + let pkg_description = pkg + .description + .unwrap_or_else(|| "No description found.".parse().unwrap()); conn.execute("INSERT OR REPLACE INTO packages (name, version, description, depends, make_depends) VALUES (?1, ?2, ?3, ?4, ?5)", - [&pkg.name, &pkg.version, &pkg.description.unwrap_or_else(|| "No description found.".parse().unwrap()), &pkg.depends.join(" "), &pkg.make_depends.join(" ")], + [&pkg.name, &pkg.version, &pkg_description, &pkg.depends.join(" "), &pkg.make_depends.join(" ")], ).unwrap_or_else(|e| - crash(format!("Failed adding package {} to the database: {}", pkg.name, e), AppExitCode::FailedAddingPkg) + crash!(AppExitCode::FailedAddingPkg, "Failed adding package {} to the database: {}", pkg.name, e) ); } diff --git a/src/database/initialise.rs b/src/database/initialise.rs index 89105d7..20fa80f 100644 --- a/src/database/initialise.rs +++ b/src/database/initialise.rs @@ -12,14 +12,14 @@ pub fn init(options: Options) { let verbosity = options.verbosity; if verbosity >= 1 { - log(format!("Creating database at {}", &path)); + log!("Creating database at {}", &path); } let conn = Connection::open(dbpath).expect("Couldn't create database at ~/.local/share/ame/db.sqlite"); if verbosity >= 1 { - log("Populating database with table".to_string()); + log!("Populating database with table"); } conn.execute( @@ -33,9 +33,10 @@ pub fn init(options: Options) { [], ) .unwrap_or_else(|e| { - crash( - format!("Couldn't initialise database: {}", e), + crash!( AppExitCode::FailedInitDb, + "Couldn't initialise database: {}", + e, ) }); } diff --git a/src/database/mod.rs b/src/database/mod.rs index 705843c..58652c7 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -3,7 +3,16 @@ mod initialise; mod query; mod remove; +use std::{env, path::PathBuf}; + pub use add::*; pub use initialise::*; pub use query::*; pub use remove::*; +use rusqlite::Connection; + +fn get_database_connection() -> Connection { + let db_path = format!("{}/.local/share/ame/db.sqlite", env::var("HOME").unwrap()); + let conn = Connection::open(PathBuf::from(db_path)).expect("Couldn't connect to database"); + conn +} diff --git a/src/database/query.rs b/src/database/query.rs index d12470d..251065c 100644 --- a/src/database/query.rs +++ b/src/database/query.rs @@ -10,7 +10,7 @@ pub fn query(options: Options) -> Vec { let verbosity = options.verbosity; if verbosity >= 1 { - log("Connecting to database".to_string()); + log!("Connecting to database"); } let conn = Connection::open(Path::new(&format!( @@ -20,7 +20,7 @@ pub fn query(options: Options) -> Vec { .expect("Couldn't connect to database"); if verbosity >= 1 { - log("Querying database for input".to_string()); + log!("Querying database for input"); } let mut rs = conn.prepare("SELECT * FROM packages;").unwrap(); @@ -47,7 +47,7 @@ pub fn query(options: Options) -> Vec { .expect("Couldn't query database for packages"); if verbosity >= 1 { - log("Retrieved results".to_string()); + log!("Retrieved results"); } let mut results: Vec = vec![]; @@ -57,7 +57,7 @@ pub fn query(options: Options) -> Vec { } if verbosity >= 1 { - log("Collected results".to_string()); + log!("Collected results"); } results diff --git a/src/database/remove.rs b/src/database/remove.rs index c213e3b..ef1e5da 100644 --- a/src/database/remove.rs +++ b/src/database/remove.rs @@ -1,21 +1,14 @@ -use std::env; -use std::path::Path; - -use rusqlite::Connection; - use crate::{log, Options}; +use super::get_database_connection; + pub fn remove(pkg: &str, options: Options) { - let conn = Connection::open(Path::new(&format!( - "{}/.local/share/ame/db.sqlite", - env::var("HOME").unwrap() - ))) - .expect("Couldn't connect to database"); + let conn = get_database_connection(); let verbosity = options.verbosity; if verbosity >= 1 { - log(format!("Removing package {} from database", pkg)); + log!("Removing package {} from database", pkg); } conn.execute( diff --git a/src/internal/clean.rs b/src/internal/clean.rs index f6fbcc5..5d3f0f3 100644 --- a/src/internal/clean.rs +++ b/src/internal/clean.rs @@ -1,7 +1,6 @@ use regex::Regex; -use crate::internal::strings::log; -use crate::Options; +use crate::{log, Options}; pub fn clean(a: &[String], options: Options) -> Vec { let r = Regex::new(r"(\S+)((?:>=|<=|>|<)\S+$)").unwrap(); @@ -18,7 +17,7 @@ pub fn clean(a: &[String], options: Options) -> Vec { } if verbosity >= 1 { - log(format!("Cleaned: {:?}\nInto: {:?}", a, cleaned)); + log!("Cleaned: {:?}\nInto: {:?}", a, cleaned); } cleaned diff --git a/src/internal/detect.rs b/src/internal/detect.rs deleted file mode 100644 index 28166c2..0000000 --- a/src/internal/detect.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::internal::strings::info; - -pub fn detect(a: String) { - if a.contains(".pacnew") || a.contains(".new") { - info("It appears that a program you have installed / upgraded has installed a .new/.pacnew config file. Please read over the pacman output and act on it accordingly".to_string()); - } else if a.contains(".old") { - info("It appears that a program you have installed / upgraded has installed a .old config file. Please read over the pacman output and act on it accordingly".to_string()); - } -} diff --git a/src/internal/error.rs b/src/internal/error.rs index 02e3010..2dfc774 100644 --- a/src/internal/error.rs +++ b/src/internal/error.rs @@ -1,5 +1,5 @@ -use crate::crash; use crate::internal::exit_code::AppExitCode; +use crate::log_and_crash; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::io; @@ -51,7 +51,7 @@ impl SilentUnwrap for AppResult { fn silent_unwrap(self, exit_code: AppExitCode) -> T { match self { Ok(val) => val, - Err(_) => crash("an error occurred", exit_code), + Err(_) => log_and_crash("an error occurred", exit_code), } } } diff --git a/src/internal/initialise.rs b/src/internal/initialise.rs index 200f14a..57c3d4f 100644 --- a/src/internal/initialise.rs +++ b/src/internal/initialise.rs @@ -3,8 +3,7 @@ use std::env; use std::path::Path; use std::process::Command; -use crate::internal::strings::{crash, log}; -use crate::Options; +use crate::{crash, log, Options}; pub fn init(options: Options) { let verbosity = options.verbosity; @@ -15,13 +14,15 @@ pub fn init(options: Options) { match r { Ok(_) => { if verbosity >= 1 { - log(format!("Created path: {}/.local/share/ame", homedir)); + log!("Created path: {}/.local/share/ame", homedir); } } Err(e) => { - crash( - format!("Couldn't create path: {}/.local/share/ame: {}", homedir, e), + crash!( AppExitCode::FailedCreatingPaths, + "Couldn't create path: {}/.local/share/ame: {}", + homedir, + e, ); } } @@ -36,13 +37,15 @@ pub fn init(options: Options) { match r { Ok(_) => { if verbosity >= 1 { - log(format!("Created path: {}/.cache/ame", homedir)); + log!("Created path: {}/.cache/ame", homedir); } } Err(e) => { - crash( - format!("Couldn't create path: {}/.cache/ame: {}", homedir, e), + crash!( AppExitCode::FailedCreatingPaths, + "Couldn't create path: {}/.cache/ame: {}", + homedir, + e, ); } } @@ -51,13 +54,15 @@ pub fn init(options: Options) { match r { Ok(_) => { if verbosity >= 1 { - log(format!("Removing cache: {}/.cache/ame", homedir)); + log!("Removing cache: {}/.cache/ame", homedir); } } Err(e) => { - crash( - format!("Couldn't remove path: {}/.cache/ame: {}", homedir, e), + crash!( AppExitCode::FailedCreatingPaths, + "Couldn't remove path: {}/.cache/ame: {}", + homedir, + e, ); } } @@ -65,13 +70,15 @@ pub fn init(options: Options) { match r2 { Ok(_) => { if verbosity >= 1 { - log(format!("Created path: {}/.cache/ame", homedir)); + log!("Created path: {}/.cache/ame", homedir); } } Err(e2) => { - crash( - format!("Couldn't create path: {}/.cache/ame: {}", homedir, e2), + crash!( AppExitCode::FailedCreatingPaths, + "Couldn't create path: {}/.cache/ame: {}", + homedir, + e2, ); } } @@ -85,19 +92,15 @@ pub fn init(options: Options) { match r { Ok(_) => { if verbosity >= 1 { - log(format!( - "Set correct permissions for path: {}/.cache/ame", - homedir - )); + log!("Set correct permissions for path: {}/.cache/ame", homedir); } } Err(e) => { - crash( - format!( - "Couldn't set permissions for path: {}/.cache/ame: {}", - homedir, e - ), + crash!( AppExitCode::FailedCreatingPaths, + "Couldn't set permissions for path: {}/.cache/ame: {}", + homedir, + e, ); } }; @@ -109,19 +112,18 @@ pub fn init(options: Options) { match r { Ok(_) => { if verbosity >= 1 { - log(format!( + log!( "Set correct permissions for path: {}/.local/share/ame", homedir - )); + ); } } Err(e) => { - crash( - format!( - "Couldn't set permissions for path: {}/.local/share/ame: {}", - homedir, e - ), + crash!( AppExitCode::FailedCreatingPaths, + "Couldn't set permissions for path: {}/.local/share/ame: {}", + homedir, + e, ); } }; diff --git a/src/internal/mod.rs b/src/internal/mod.rs index 5f8be49..a5e1cd2 100644 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -5,14 +5,15 @@ pub mod exit_code; mod initialise; pub mod rpc; mod sort; -mod strings; pub mod structs; +#[macro_use] +pub(crate) mod utils; pub use clean::*; pub use initialise::*; pub use sort::*; use std::env; -pub use strings::*; +pub use utils::*; #[macro_export] macro_rules! uwu { diff --git a/src/internal/sort.rs b/src/internal/sort.rs index 93b6896..d64747c 100644 --- a/src/internal/sort.rs +++ b/src/internal/sort.rs @@ -1,8 +1,7 @@ use std::process::{Command, Stdio}; -use crate::internal::strings::log; use crate::internal::{clean, rpc, structs}; -use crate::Options; +use crate::{log, Options}; pub fn sort(input: &[String], options: Options) -> structs::Sorted { let mut repo: Vec = vec![]; @@ -13,7 +12,7 @@ pub fn sort(input: &[String], options: Options) -> structs::Sorted { let a = clean(input, options); if verbosity >= 1 { - log(format!("Sorting: {:?}", a.join(" "))); + log!("Sorting: {:?}", a.join(" ")); } for b in a { @@ -26,17 +25,17 @@ pub fn sort(input: &[String], options: Options) -> structs::Sorted { if let Some(0) = rs.code() { if verbosity >= 1 { - log(format!("{} found in repos", b)); + log!("{} found in repos", b); } repo.push(b.to_string()); } else if rpc::rpcinfo(b.to_string()).found { if verbosity >= 1 { - log(format!("{} found in AUR", b)); + log!("{} found in AUR", b); } aur.push(b.to_string()); } else { if verbosity >= 1 { - log(format!("{} not found", b)); + log!("{} not found", b); } nf.push(b.to_string()); } diff --git a/src/internal/strings.rs b/src/internal/strings.rs deleted file mode 100644 index 3ffe71d..0000000 --- a/src/internal/strings.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::io; -use std::io::Write; -use std::process::exit; -use std::time::UNIX_EPOCH; - -use crate::internal::exit_code::AppExitCode; -use crate::{internal, uwu}; - -pub fn info(msg: S) { - let a = msg.to_string(); - let a = if internal::uwu_enabled() { uwu!(&a) } else { a }; - - println!("\x1b[2;22;35m❖\x1b[0m \x1b[1;37m{}\x1b[0m", a) -} - -pub fn crash(msg: S, exit_code: AppExitCode) -> ! { - let a = msg.to_string(); - let a = if internal::uwu_enabled() { uwu!(&a) } else { a }; - - println!("\x1b[2;22;31m❌:\x1b[0m \x1b[1;91m{}\x1b[0m", a); - exit(exit_code as i32); -} - -pub fn log(msg: S) { - let a = msg.to_string(); - let a = if internal::uwu_enabled() && internal::uwu_debug_enabled() { - uwu!(&a) - } else { - a - }; - - eprintln!( - "{} {}", - std::time::SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - a - ); -} - -pub fn prompt(a: S, b: bool) -> bool { - let a = a.to_string(); - let default = ["[Y/n]", "[y/N]"]; - let i = if b { 0 } else { 1 }; - - let a = if internal::uwu_enabled() { uwu!(&a) } else { a }; - - print!( - "\x1b[2;22;35m?\x1b[0m \x1b[1;37m{}\x1b[0m \x1b[2;22;37m{}\x1b[0m: ", - a, default[i] - ); - - let mut yn: String = String::new(); - - io::stdout().flush().ok(); - let _ = std::io::stdin().read_line(&mut yn); - - if yn.trim().to_lowercase() == "n" || yn.trim().to_lowercase() == "no" { - false - } else if yn.trim().to_lowercase() == "y" || yn.trim().to_lowercase() == "yes" { - true - } else { - b - } -} diff --git a/src/internal/utils.rs b/src/internal/utils.rs new file mode 100644 index 0000000..eef9441 --- /dev/null +++ b/src/internal/utils.rs @@ -0,0 +1,120 @@ +use std::io; +use std::io::Write; +use std::process::exit; +use std::time::UNIX_EPOCH; + +use crate::internal::exit_code::AppExitCode; +use crate::{internal, uwu}; +use colored::*; + +const OK_SYMBOL: &str = "❖"; +const ERR_SYMBOL: &str = "❌"; +const PROMPT_SYMBOL: &str = "?"; + +const PROMPT_YN_DEFAULT_TRUE: &str = "[Y/n]"; +const PROMPT_YN_DEFAULT_FALSE: &str = "[y/N]"; + +#[macro_export] +macro_rules! info { + ($($arg:tt)+) => { + $crate::internal::utils::log_info(format!($($arg)+)) + } +} + +#[macro_export] +macro_rules! crash { + ($exit_code:expr, $($arg:tt)+) => { + $crate::internal::utils::log_and_crash(format!($($arg)+), $exit_code) + } +} + +#[macro_export] +macro_rules! log { + ($($arg:tt)+) => { + $crate::internal::utils::log_debug(format!($($arg)+)) + } +} + +#[macro_export] +macro_rules! prompt { + (default $default:expr, $($arg:tt)+) => { + $crate::internal::utils::prompt_yn(format!($($arg)+), $default) + } +} + +pub fn log_info(msg: S) { + let msg = msg.to_string(); + let msg = if internal::uwu_enabled() { + uwu!(&msg) + } else { + msg + }; + + println!("{} {}", OK_SYMBOL.purple(), msg.bold()) +} + +pub fn log_and_crash(msg: S, exit_code: AppExitCode) -> ! { + let msg = msg.to_string(); + let msg = if internal::uwu_enabled() { + uwu!(&msg) + } else { + msg + }; + + println!("{}: {}", ERR_SYMBOL.red().bold(), msg.red().bold()); + exit(exit_code as i32); +} + +pub fn log_debug(msg: S) { + let msg = msg.to_string(); + let msg = if internal::uwu_enabled() && internal::uwu_debug_enabled() { + uwu!(&msg) + } else { + msg + }; + + eprintln!( + "{} {}", + std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + msg + ); +} + +pub fn prompt_yn(question: S, default_true: bool) -> bool { + let question = question.to_string(); + + let yn_prompt = if default_true { + PROMPT_YN_DEFAULT_TRUE + } else { + PROMPT_YN_DEFAULT_FALSE + }; + + let question = if internal::uwu_enabled() { + uwu!(&question) + } else { + question + }; + + print!( + "{} {} {}: ", + PROMPT_SYMBOL.purple(), + question.bold(), + yn_prompt + ); + + let mut yn: String = String::new(); + + io::stdout().flush().ok(); + let _ = std::io::stdin().read_line(&mut yn); + + if yn.trim().to_lowercase() == "n" || yn.trim().to_lowercase() == "no" { + false + } else if yn.trim().to_lowercase() == "y" || yn.trim().to_lowercase() == "yes" { + true + } else { + default_true + } +} diff --git a/src/main.rs b/src/main.rs index a9742b5..0a9ea9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use internal::commands::ShellCommand; use internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; -use crate::internal::{crash, info, init, log, sort, structs::Options}; +use crate::internal::{init, log_and_crash, log_info, sort, structs::Options}; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -18,7 +18,7 @@ mod operations; fn main() { if unsafe { libc::geteuid() } == 0 { - crash("Running amethyst as root is disallowed as it can lead to system breakage. Instead, amethyst will prompt you when it needs superuser permissions".to_string(), AppExitCode::RunAsRoot); + log_and_crash("Running amethyst as root is disallowed as it can lead to system breakage. Instead, amethyst will prompt you when it needs superuser permissions".to_string(), AppExitCode::RunAsRoot); } let args: Args = Args::parse(); @@ -40,7 +40,7 @@ fn main() { Operation::Search(search_args) => cmd_search(search_args, options), Operation::Query(query_args) => cmd_query(query_args), Operation::Upgrade => { - info("Performing system upgrade".to_string()); + log_info("Performing system upgrade".to_string()); operations::upgrade(options); } } @@ -50,7 +50,7 @@ fn cmd_install(args: InstallArgs, options: Options) { let packages = args.packages; let sorted = sort(&packages, options); - info(format!( + log_info(format!( "Attempting to install packages: {}", packages.join(", ") )); @@ -62,7 +62,7 @@ fn cmd_install(args: InstallArgs, options: Options) { operations::aur_install(sorted.aur, options); } if !sorted.nf.is_empty() { - crash( + log_and_crash( format!( "Couldn't find packages: {} in repos or the AUR", sorted.nf.join(", ") @@ -83,29 +83,29 @@ fn cmd_install(args: InstallArgs, options: Options) { .split_whitespace() .collect::>() .join(", "); - info(format!("You have .pacnew files in /etc ({pacnew_files}) that you haven't removed or acted upon, it is recommended you do that now", )); + log_info(format!("You have .pacnew files in /etc ({pacnew_files}) that you haven't removed or acted upon, it is recommended you do that now", )); } } fn cmd_remove(args: RemoveArgs, options: Options) { let packages = args.packages; - info(format!("Uninstalling packages: {}", &packages.join(", "))); + log_info(format!("Uninstalling packages: {}", &packages.join(", "))); operations::uninstall(packages, options); } fn cmd_search(args: SearchArgs, options: Options) { let query_string = args.search.join(" "); if args.aur { - info(format!("Searching AUR for {}", &query_string)); + log_info(format!("Searching AUR for {}", &query_string)); operations::aur_search(&query_string, options); } if args.repo { - info(format!("Searching repos for {}", &query_string)); + log_info(format!("Searching repos for {}", &query_string)); operations::search(&query_string, options); } if !args.aur && !args.repo { - info(format!("Searching AUR and repos for {}", &query_string)); + log_info(format!("Searching AUR and repos for {}", &query_string)); operations::search(&query_string, options); operations::aur_search(&query_string, options); } diff --git a/src/operations/aur_install.rs b/src/operations/aur_install.rs index 9d1be84..dfe3714 100644 --- a/src/operations/aur_install.rs +++ b/src/operations/aur_install.rs @@ -8,8 +8,7 @@ use crate::internal::commands::ShellCommand; use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; use crate::internal::rpc::rpcinfo; -use crate::internal::{crash, prompt}; -use crate::{info, log, Options}; +use crate::{crash, info, log, prompt, Options}; pub fn aur_install(a: Vec, options: Options) { let url = crate::internal::rpc::URL; @@ -18,10 +17,10 @@ pub fn aur_install(a: Vec, options: Options) { let noconfirm = options.noconfirm; if verbosity >= 1 { - log(format!("Installing from AUR: {:?}", &a)); + log!("Installing from AUR: {:?}", &a); } - info(format!("Installing packages {} from the AUR", a.join(", "))); + info!("Installing packages {} from the AUR", a.join(", ")); for package in a { let rpcres = rpcinfo(package); @@ -33,10 +32,10 @@ pub fn aur_install(a: Vec, options: Options) { let pkg = &rpcres.package.as_ref().unwrap().name; if verbosity >= 1 { - log(format!("Cloning {} into cachedir", pkg)); + log!("Cloning {} into cachedir", pkg); } - info("Cloning package source".to_string()); + info!("Cloning package source"); set_current_dir(Path::new(&cachedir)).unwrap(); ShellCommand::git() @@ -46,38 +45,32 @@ pub fn aur_install(a: Vec, options: Options) { .silent_unwrap(AppExitCode::GitError); if verbosity >= 1 { - log(format!( + log!( "Cloned {} into cachedir, moving on to resolving dependencies", pkg - )); - log(format!( + ); + log!( "Raw dependencies for package {} are:\n{:?}", pkg, rpcres.package.as_ref().unwrap().depends.join(", ") - )); - log(format!( + ); + log!( "Raw makedepends for package {} are:\n{:?}", pkg, rpcres.package.as_ref().unwrap().make_depends.join(", ") - )); + ); } // dep sorting - info("Sorting dependencies".to_string()); + log!("Sorting dependencies"); let sorted = crate::internal::sort(&rpcres.package.as_ref().unwrap().depends, options); - info("Sorting make dependencies".to_string()); + log!("Sorting make dependencies"); let md_sorted = crate::internal::sort(&rpcres.package.as_ref().unwrap().make_depends, options); if verbosity >= 1 { - log(format!( - "Sorted dependencies for {} are:\n{:?}", - pkg, &sorted - )); - log(format!( - "Sorted makedepends for {} are:\n{:?}", - pkg, &md_sorted - )); + log!("Sorted dependencies for {} are:\n{:?}", pkg, &sorted); + log!("Sorted makedepends for {} are:\n{:?}", pkg, &md_sorted); } let newopts = Options { @@ -87,23 +80,18 @@ pub fn aur_install(a: Vec, options: Options) { }; if !sorted.nf.is_empty() || !md_sorted.nf.is_empty() { - crash( - format!( - "Could not find dependencies {} for package {}, aborting", - sorted.nf.join(", "), - pkg - ), + crash!( AppExitCode::MissingDeps, + "Could not find dependencies {} for package {}, aborting", + sorted.nf.join(", "), + pkg, ); } if !noconfirm { - let p1 = prompt( - format!( - "Would you like to review {}'s PKGBUILD (and any .install files if present)?", - pkg - ), - false, + let p1 = prompt!(default false, + "Would you like to review {}'s PKGBUILD (and any .install files if present)?", + pkg ); let editor: &str = &env::var("PAGER").unwrap_or_else(|_| "less".parse().unwrap()); @@ -129,16 +117,17 @@ pub fn aur_install(a: Vec, options: Options) { .silent_unwrap(AppExitCode::Other); } - let p2 = prompt(format!("Would you still like to install {}?", pkg), true); + let p2 = prompt!(default true, "Would you still like to install {}?", pkg); if !p2 { fs::remove_dir_all(format!("{}/{}", cachedir, pkg)).unwrap(); - crash("Not proceeding".to_string(), AppExitCode::UserCancellation); + crash!(AppExitCode::UserCancellation, "Not proceeding"); } } } // dep installing - info("Moving on to install dependencies".to_string()); + info!("Moving on to install dependencies"); + if !sorted.repo.is_empty() { crate::operations::install(sorted.repo, newopts); crate::operations::install(md_sorted.repo, newopts); @@ -157,7 +146,7 @@ pub fn aur_install(a: Vec, options: Options) { } // package building and installing - info("Building time!".to_string()); + info!("Building time!"); set_current_dir(format!("{}/{}", cachedir, pkg)).unwrap(); let status = ShellCommand::makepkg() .args(makepkg_args) @@ -166,9 +155,10 @@ pub fn aur_install(a: Vec, options: Options) { if !status.success() { fs::remove_dir_all(format!("{}/{}", cachedir, pkg)).unwrap(); - crash( - format!("Error encountered while installing {}, aborting", pkg), + crash!( AppExitCode::PacmanError, + "Error encountered while installing {}, aborting", + pkg, ); } diff --git a/src/operations/install.rs b/src/operations/install.rs index d1f1c59..2de6272 100644 --- a/src/operations/install.rs +++ b/src/operations/install.rs @@ -4,10 +4,7 @@ use crate::internal::exit_code::AppExitCode; use crate::{crash, info, log, Options}; pub fn install(packages: Vec, options: Options) { - info(format!( - "Installing packages {} from repos", - &packages.join(", ") - )); + info!("Installing packages {} from repos", &packages.join(", ")); let mut opers = vec!["-S", "--needed"]; if options.noconfirm { opers.push("--noconfirm"); @@ -19,7 +16,7 @@ pub fn install(packages: Vec, options: Options) { if !packages.is_empty() { if verbosity >= 1 { - log(format!("Installing from repos: {:?}", &packages)); + log!("Installing from repos: {:?}", &packages); } let status = ShellCommand::pacman() @@ -29,20 +26,15 @@ pub fn install(packages: Vec, options: Options) { .wait() .silent_unwrap(AppExitCode::PacmanError); if !status.success() { - crash( - format!( - "An error occured while installing packages: {}, aborting", - packages.join(", ") - ), + crash!( AppExitCode::PacmanError, + "An error occured while installing packages: {}, aborting", + packages.join(", "), ); } if verbosity >= 1 { - log(format!( - "Installing packages: {:?} was successful", - &packages - )); + log!("Installing packages: {:?} was successful", &packages); } } } diff --git a/src/operations/search.rs b/src/operations/search.rs index b837133..0303602 100644 --- a/src/operations/search.rs +++ b/src/operations/search.rs @@ -21,10 +21,7 @@ pub fn aur_search(query: &str, options: Options) { } if verbosity >= 1 { - log(format!( - "Found {} resuls for \"{}\" in AUR", - res.resultcount, query - )); + log!("Found {} resuls for \"{}\" in AUR", res.resultcount, query); } } @@ -38,11 +35,11 @@ pub fn repo_search(query: &str, options: Options) { .stdout; if verbosity >= 1 { - log(format!( + log!( "Found {} results for \"{}\" in repos", &output.split('\n').count() / 2, &query - )); + ); } println!("{}", output) diff --git a/src/operations/uninstall.rs b/src/operations/uninstall.rs index e7e51a6..646e65a 100644 --- a/src/operations/uninstall.rs +++ b/src/operations/uninstall.rs @@ -15,7 +15,7 @@ pub fn uninstall(packages: Vec, options: Options) { } let verbosity = options.verbosity; if verbosity >= 1 { - log(format!("Uninstalling: {:?}", &packages)); + log!("Uninstalling: {:?}", &packages); } ShellCommand::pacman() @@ -25,10 +25,7 @@ pub fn uninstall(packages: Vec, options: Options) { .silent_unwrap(AppExitCode::PacmanError); if verbosity >= 1 { - log(format!( - "Uninstalling packages: {:?} exited with code 0", - &packages - )); + log!("Uninstalling packages: {:?} exited with code 0", &packages); } for package in packages { @@ -41,7 +38,7 @@ pub fn uninstall(packages: Vec, options: Options) { .exists() { if verbosity >= 1 { - log("Old cache directory found, deleting".to_string()); + log!("Old cache directory found, deleting"); } fs::remove_dir_all(Path::new(&format!( "{}/.cache/ame/{}", diff --git a/src/operations/upgrade.rs b/src/operations/upgrade.rs index f03d20d..fb00f6b 100644 --- a/src/operations/upgrade.rs +++ b/src/operations/upgrade.rs @@ -15,7 +15,7 @@ pub fn upgrade(options: Options) { } if verbosity >= 1 { - log("Upgrading repo packages".to_string()); + log!("Upgrading repo packages"); } ShellCommand::pacman() @@ -25,13 +25,13 @@ pub fn upgrade(options: Options) { .silent_unwrap(AppExitCode::PacmanError); if verbosity >= 1 { - log("Upgrading AUR packages".to_string()); + log!("Upgrading AUR packages"); } let res = crate::database::query(options); if verbosity >= 1 { - log(format!("{:?}", &res)); + log!("{:?}", &res); } let mut aur_upgrades = vec![]; @@ -46,6 +46,6 @@ pub fn upgrade(options: Options) { if !aur_upgrades.is_empty() { aur_install(aur_upgrades, options); } else { - info("No upgrades available for installed AUR packages".to_string()); + info!("No upgrades available for installed AUR packages"); } } From 7baaced9056b9034aa9c548c143a4fd333ea385a Mon Sep 17 00:00:00 2001 From: trivernis Date: Tue, 5 Jul 2022 20:51:14 +0200 Subject: [PATCH 4/7] Fix the one and only clippy warning Signed-off-by: trivernis --- src/database/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index aa3d240..4eb9d9a 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -13,6 +13,5 @@ use rusqlite::Connection; fn get_database_connection() -> Connection { let db_path = format!("{}/.local/share/ame/db.sqlite", env::var("HOME").unwrap()); - let conn = Connection::open(PathBuf::from(db_path)).expect("Couldn't connect to database"); - conn + Connection::open(PathBuf::from(db_path)).expect("Couldn't connect to database") } From d49a529a32ff7fa945a94ee01af58a6b30cc0f92 Mon Sep 17 00:00:00 2001 From: Michal Date: Sat, 16 Jul 2022 12:56:47 +0100 Subject: [PATCH 5/7] Added vim dependency for pacdiff --- PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PKGBUILD b/PKGBUILD index 0d2c390..9d580ec 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -11,7 +11,7 @@ url="https://github.com/crystal-linux/amethyst" license=('GPL3') source=("git+$url") sha256sums=('SKIP') -depends=('git' 'binutils' 'fakeroot' 'pacman-contrib') +depends=('git' 'binutils' 'fakeroot' 'pacman-contrib' 'vim') makedepends=('cargo') conflicts=('ame') From 3bd00ed919ac51c3205fd65523fc93351fdd8513 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 18 Jul 2022 20:32:39 +0100 Subject: [PATCH 6/7] Bumped pkgrel --- PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PKGBUILD b/PKGBUILD index 9d580ec..3198600 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -4,7 +4,7 @@ pkgname=amethyst pkgver=3.3.0 -pkgrel=1 +pkgrel=2 pkgdesc="A fast and efficient AUR helper" arch=('x86_64') url="https://github.com/crystal-linux/amethyst" From 68a13e58ed1cac4530d5dc21d4df02d13eaecf24 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 18 Jul 2022 20:33:23 +0100 Subject: [PATCH 7/7] Re-added `rem` alias for remove command --- src/args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/args.rs b/src/args.rs index 8a78826..ac1827c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -26,7 +26,7 @@ pub enum Operation { Install(InstallArgs), /// Removes a previously installed package - #[clap(name = "remove", aliases = & ["rm", "r", "-R", "-Rs"])] + #[clap(name = "remove", aliases = & ["rm", "rem", "r", "-R", "-Rs"])] Remove(RemoveArgs), /// Searches for the relevant packages in both the AUR and repos