Proper Result
and error structure for input prompts
This commit is contained in:
parent
8844bafd64
commit
828da40579
7 changed files with 68 additions and 25 deletions
|
@ -44,7 +44,7 @@ use crate::{
|
|||
filesystem::{create_blank_state, create_hard_link},
|
||||
transaction::{TransactionAggregator, TransactionFlags},
|
||||
},
|
||||
utils::unix_epoch_time,
|
||||
utils::{prompt::PromptError, unix_epoch_time},
|
||||
Error,
|
||||
ErrorGeneric,
|
||||
ErrorTrait,
|
||||
|
@ -131,6 +131,10 @@ impl ErrorTrait for SyncError {
|
|||
|
||||
impl From<&Error> for SyncError {
|
||||
fn from(error: &Error) -> SyncError {
|
||||
if let Ok(PromptError::PromptInterrupted) = error.downcast::<PromptError>() {
|
||||
return Self::SignalInterrupt;
|
||||
}
|
||||
|
||||
Self::InternalError(error.kind().to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use std::path::Path;
|
|||
|
||||
use alpm::{AnyQuestion, Question::*};
|
||||
|
||||
use crate::utils::prompt::prompt;
|
||||
use crate::{utils::prompt::prompt, ErrorGeneric};
|
||||
|
||||
pub fn callback(question: AnyQuestion, _: &mut ()) {
|
||||
match question.question() {
|
||||
|
@ -30,8 +30,9 @@ pub fn callback(question: AnyQuestion, _: &mut ()) {
|
|||
let pkg_b = x.conflict().package2().name();
|
||||
let prompt_string = format!("Conflict between {pkg_a} and {pkg_b}; Remove {pkg_b}?");
|
||||
|
||||
if prompt("->", prompt_string, false) {
|
||||
x.set_remove(true);
|
||||
match prompt("->", prompt_string, false).generic() {
|
||||
Ok(bool) => x.set_remove(bool),
|
||||
Err(err) => err.error(),
|
||||
}
|
||||
}
|
||||
Replace(x) => {
|
||||
|
@ -39,8 +40,9 @@ pub fn callback(question: AnyQuestion, _: &mut ()) {
|
|||
let new = x.newpkg().name();
|
||||
let prompt_string = format!("Replace package {old} with {new}?");
|
||||
|
||||
if prompt("->", prompt_string, false) {
|
||||
x.set_replace(true);
|
||||
match prompt("->", prompt_string, false).generic() {
|
||||
Ok(bool) => x.set_replace(bool),
|
||||
Err(err) => err.error(),
|
||||
}
|
||||
}
|
||||
Corrupted(mut x) => {
|
||||
|
@ -49,8 +51,9 @@ pub fn callback(question: AnyQuestion, _: &mut ()) {
|
|||
let reason = x.reason();
|
||||
let prompt_string = format!("'{filename}': {reason}. Remove package?");
|
||||
|
||||
if prompt("::", prompt_string, true) {
|
||||
x.set_remove(true);
|
||||
match prompt("->", prompt_string, false).generic() {
|
||||
Ok(bool) => x.set_remove(bool),
|
||||
Err(err) => err.error(),
|
||||
}
|
||||
}
|
||||
ImportKey(mut x) => {
|
||||
|
@ -58,8 +61,9 @@ pub fn callback(question: AnyQuestion, _: &mut ()) {
|
|||
let name = x.uid();
|
||||
let prompt_string = format!("Import key {fingerprint}, \"{name}\" to keyring?");
|
||||
|
||||
if prompt("->", prompt_string, true) {
|
||||
x.set_import(true);
|
||||
match prompt("->", prompt_string, false).generic() {
|
||||
Ok(bool) => x.set_import(bool),
|
||||
Err(err) => err.error(),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
|
|
@ -436,7 +436,7 @@ impl<'a> TransactionHandle<'a> {
|
|||
if !self.agent
|
||||
&& !ignored.contains(pkg.name())
|
||||
&& config.alpm().held().contains(&pkg.name())
|
||||
&& !prompt("::", format!("Target package {}{}{} is held. Remove it?", *BOLD, pkg.name(), *RESET), false)
|
||||
&& !prompt("::", format!("Target package {}{}{} is held. Remove it?", *BOLD, pkg.name(), *RESET), false)?
|
||||
{
|
||||
self.meta.held_pkgs.insert(pkg.name().into());
|
||||
continue;
|
||||
|
@ -466,7 +466,7 @@ impl<'a> TransactionHandle<'a> {
|
|||
"::",
|
||||
format!("Target package {}{}{} is ignored. Upgrade it?", *BOLD, pkg.name(), *RESET),
|
||||
false,
|
||||
)
|
||||
)?
|
||||
{
|
||||
self.meta.ignored_pkgs.insert(pkg.name().into());
|
||||
continue;
|
||||
|
|
|
@ -17,24 +17,51 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::{
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
io::ErrorKind::{Interrupted, NotConnected},
|
||||
};
|
||||
|
||||
use dialoguer::{
|
||||
console::{style, Style},
|
||||
theme::ColorfulTheme,
|
||||
Input,
|
||||
};
|
||||
use std::io::Error;
|
||||
|
||||
use crate::constants::{BAR_RED, BOLD, RESET};
|
||||
use crate::{
|
||||
constants::{BAR_RED, BOLD, RESET},
|
||||
err,
|
||||
impl_error,
|
||||
Error,
|
||||
ErrorGeneric,
|
||||
ErrorTrait,
|
||||
Result,
|
||||
};
|
||||
|
||||
pub fn prompt(prefix: &str, prompt: impl Into<String>, yn_prompt: bool) -> bool {
|
||||
if let Ok(value) = create_prompt(prompt.into(), prefix, yn_prompt) {
|
||||
value.to_lowercase() == "y" || (yn_prompt && value.is_empty())
|
||||
} else {
|
||||
false
|
||||
#[derive(Debug)]
|
||||
pub enum PromptError {
|
||||
PromptInterrupted,
|
||||
PromptNotTerminal,
|
||||
}
|
||||
|
||||
impl Display for PromptError {
|
||||
fn fmt(&self, fmter: &mut Formatter<'_>) -> FmtResult {
|
||||
match self {
|
||||
Self::PromptInterrupted => write!(fmter, "Prompt was interrupted."),
|
||||
Self::PromptNotTerminal => write!(fmter, "Input is not a terminal."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_prompt(message: String, prefix: &str, yn_prompt: bool) -> Result<String, Error> {
|
||||
impl_error!(PromptError);
|
||||
|
||||
pub fn prompt(prefix: &str, prompt: impl Into<String>, yn_prompt: bool) -> Result<bool> {
|
||||
let value = create_prompt(prompt.into(), prefix, yn_prompt)?;
|
||||
|
||||
Ok(value.to_lowercase() == "y" || (yn_prompt && value.is_empty()))
|
||||
}
|
||||
|
||||
fn create_prompt(message: String, prefix: &str, yn_prompt: bool) -> Result<String> {
|
||||
let prompt = match yn_prompt {
|
||||
true => ("[Y/n]", style(prefix.into()).blue().bold()),
|
||||
false => ("[y/N]", style(prefix.into()).red().bold()),
|
||||
|
@ -50,11 +77,19 @@ fn create_prompt(message: String, prefix: &str, yn_prompt: bool) -> Result<Strin
|
|||
values_style: Style::new(),
|
||||
..ColorfulTheme::default()
|
||||
};
|
||||
let input: String = match Input::with_theme(&theme).with_prompt(message).allow_empty(true).interact_text() {
|
||||
Ok(prompt) => prompt,
|
||||
Err(error) => match error.kind() {
|
||||
Interrupted => err!(PromptError::PromptInterrupted)?,
|
||||
NotConnected => err!(PromptError::PromptNotTerminal)?,
|
||||
_ => Err(error).generic()?,
|
||||
},
|
||||
};
|
||||
|
||||
return Input::with_theme(&theme).with_prompt(message).allow_empty(true).interact_text();
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
pub fn prompt_targets(targets: &[&str], ins_prompt: &str, yn_prompt: bool) -> bool {
|
||||
pub fn prompt_targets(targets: &[&str], ins_prompt: &str, yn_prompt: bool) -> Result<bool> {
|
||||
eprintln!("{} {}Container{}{}\n", *BAR_RED, *BOLD, if targets.len() > 1 { "s" } else { "" }, *RESET);
|
||||
|
||||
for target in targets.iter() {
|
||||
|
|
|
@ -72,7 +72,7 @@ fn delete_containers<'a>(
|
|||
if flags.contains(TransactionFlags::NO_CONFIRM) {
|
||||
println!("{} {}{}...{}", *BAR_GREEN, *BOLD, &message, *RESET);
|
||||
delete_roots(cache, lock, logger, delete, force)?;
|
||||
} else if prompt_targets(delete, &message, false) {
|
||||
} else if prompt_targets(delete, &message, false)? {
|
||||
delete_roots(cache, lock, logger, delete, force)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ fn process_kill(args: &mut Arguments) -> Result<()> {
|
|||
let instances: Vec<String> = instances.iter().map(|a| format!("{} ({}{}{})", a.0, *DIM, a.1, *RESET)).collect();
|
||||
let instances: Vec<&str> = instances.iter().map(|a| a.as_ref()).collect();
|
||||
|
||||
match no_confirm || prompt_targets(&instances, "Kill container processes?", false) {
|
||||
match no_confirm || prompt_targets(&instances, "Kill container processes?", false)? {
|
||||
true => kill_processes(&list, sigint),
|
||||
false => Ok(()),
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ pub fn remove_containers(args: &mut Arguments) -> Result<()> {
|
|||
|
||||
let lock = Lock::new().lock()?;
|
||||
|
||||
if let (true, _) | (_, true) = (no_confirm, prompt_targets(&instances, "Delete containers?", false)) {
|
||||
if let (true, _) | (_, true) = (no_confirm, prompt_targets(&instances, "Delete containers?", false)?) {
|
||||
if let Err(err) = delete_roots(&cache, &lock, &mut logger, &instances, force) {
|
||||
eprintln!("{}", ErrorType::Error(&err));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue