From 61a66d3755941522cee03fe22c9a9bcb0c423ca8 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 16 Apr 2026 04:04:53 +0700 Subject: [PATCH 1/3] Better error display --- src/bin/repo.rs | 60 ++++++++++++++++++++++--------------------------- src/lib.rs | 3 ++- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/bin/repo.rs b/src/bin/repo.rs index a9ee16b0..47ff8b7c 100644 --- a/src/bin/repo.rs +++ b/src/bin/repo.rs @@ -134,10 +134,7 @@ impl FromStr for CliCommand { "push-tree" => Ok(CliCommand::PushTree), "cook-tree" => Ok(CliCommand::CookTree), "find" => Ok(CliCommand::Find), - _ => Err(Error::Other(format!( - "Unknown command '{}'\n{}\n", - s, REPO_HELP_STR - ))), + _ => bail_options_err!("Unknown command {:?}", s), } } } @@ -188,7 +185,10 @@ impl CliConfig { fn main() { init_config(); if let Err(e) = main_inner() { - eprintln!("{:?}", e); + match e { + Error::Options(e) => eprintln!("{}\n{}", e, REPO_HELP_STR), + e => eprintln!("{}", e), + } process::exit(1); }; } @@ -197,8 +197,7 @@ fn main_inner() -> Result<()> { let args: Vec = env::args().skip(1).collect(); if args.is_empty() || args.contains(&"--help".to_string()) || args.contains(&"-h".to_string()) { - println!("{}", REPO_HELP_STR); - process::exit(1); + bail_options_err!(""); } let (config, command, recipes) = parse_args(args)?; @@ -259,10 +258,10 @@ fn main_inner() -> Result<()> { Err(e) => { if config.cook.nonstop { if verbose { - eprintln!("{:?}", e); + eprintln!("{}", e); } if let Err(e) = handle_nonstop_fail(recipe) { - eprintln!("{:?}", e) + eprintln!("{}", e) }; } print_failed(&command, &recipe.name); @@ -417,6 +416,12 @@ fn publish_packages(recipe_names: &Vec, repo_path: &PathBuf) -> Resu run_command(command, &None) } +macro_rules! bail_options_err { + ($($arg:tt)*) => { + return Err(cookbook::Error::Options(format!($($arg)*))) + }; +} + fn parse_args(args: Vec) -> Result<(CliConfig, CliCommand, Vec)> { let mut config = CliConfig::new()?; let mut command: Option = None; @@ -433,13 +438,10 @@ fn parse_args(args: Vec) -> Result<(CliConfig, CliCommand, Vec { config.filesystem = Some({ let r = redox_installer::Config::from_file(&PathBuf::from(value)); - r.map_err(|e| Error::Other(e.to_string()))? + r.map_err(|e| Error::Other(format!("{:?}", e)))? }) } - _ => { - eprintln!("Error: Unknown flag with value: {}", arg); - process::exit(1); - } + _ => bail_options_err!("Error: Unknown flag with value: {}", arg), } } else if arg.starts_with("--category-") { // to workaround make command limit we provide this option @@ -449,18 +451,12 @@ fn parse_args(args: Vec) -> Result<(CliConfig, CliCommand, Vec override_filesystem_repo_binary = true, "--with-package-deps" => config.with_package_deps = true, "--all" => config.all = true, - _ => { - eprintln!("Error: Unknown flag: {}", arg); - process::exit(1); - } + _ => bail_options_err!("Error: Unknown flag: {}", arg), } } } else if arg.starts_with('-') { match arg.as_str() { - _ => { - eprintln!("Error: Unknown flag: {}", arg); - process::exit(1); - } + _ => bail_options_err!("Error: Unknown flag: {}", arg), } } else if command.is_none() { // The first non-flag argument is the command @@ -481,7 +477,7 @@ fn parse_args(args: Vec) -> Result<(CliConfig, CliCommand, Vec) -> Result<(CliConfig, CliCommand, Vec staged_pkg::list(""), @@ -534,9 +528,9 @@ fn parse_args(args: Vec) -> Result<(CliConfig, CliCommand, Vec write!(f, "{}", package_error), Error::Pkgar(error) => write!(f, "{}", error), - Error::Other(context) => { + Error::Other(context) | Error::Options(context) => { write!(f, "{context}") } } From 47b5176ba5b383bac781186c8b843cb12a170f20 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 16 Apr 2026 04:05:05 +0700 Subject: [PATCH 2/3] Remove dead code on queues --- src/bin/repo.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/bin/repo.rs b/src/bin/repo.rs index 47ff8b7c..11c67671 100644 --- a/src/bin/repo.rs +++ b/src/bin/repo.rs @@ -955,9 +955,6 @@ const PROMPT_WAIT: Duration = Duration::from_millis(101); struct TuiApp { recipes: Vec<(CookRecipe, RecipeStatus)>, - fetch_queue: VecDeque, - cook_queue: VecDeque, - done: Vec, active_fetch: Option, active_cook: Option, logs: HashMap>, @@ -982,9 +979,6 @@ impl TuiApp { .cloned() .map(|r| (r, RecipeStatus::Pending)) .collect(), - fetch_queue: recipes.iter().cloned().map(|r| r.clone()).collect(), - cook_queue: VecDeque::new(), - done: Vec::new(), active_fetch: None, active_cook: None, logs: HashMap::new(), @@ -1128,26 +1122,6 @@ impl TuiApp { if let Some((_, status)) = self.recipes.iter_mut().find(|(r, _)| r.name == name) { *status = new_status; } - - // Re-compute the queues for display - self.fetch_queue = self - .recipes - .iter() - .filter(|(_, s)| *s == RecipeStatus::Pending) - .map(|(r, _)| r.clone()) - .collect(); - self.cook_queue = self - .recipes - .iter() - .filter(|(_, s)| *s == RecipeStatus::Fetched) - .map(|(r, _)| r.clone()) - .collect(); - self.done = self - .recipes - .iter() - .filter(|(_, s)| *s == RecipeStatus::Done || *s == RecipeStatus::Cached) - .map(|(r, _)| r.name.clone()) - .collect(); } } From e1a68dacd73d9dd7940e6e3f3c3e83d4f8c037b7 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 16 Apr 2026 04:32:31 +0700 Subject: [PATCH 3/3] Organize tui statuses code --- src/bin/repo.rs | 115 +++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/src/bin/repo.rs b/src/bin/repo.rs index 11c67671..ca78d665 100644 --- a/src/bin/repo.rs +++ b/src/bin/repo.rs @@ -19,7 +19,7 @@ use ratatui::text::{Line, Span, Text}; use ratatui::widgets::{Block, Borders, Clear, List, ListItem, ListState, Paragraph, Wrap}; use redox_installer::PackageConfig; use std::borrow::Cow; -use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::io::{Read, Write, stderr, stdin, stdout}; use std::path::PathBuf; use std::process::Command; @@ -416,12 +416,6 @@ fn publish_packages(recipe_names: &Vec, repo_path: &PathBuf) -> Resu run_command(command, &None) } -macro_rules! bail_options_err { - ($($arg:tt)*) => { - return Err(cookbook::Error::Options(format!($($arg)*))) - }; -} - fn parse_args(args: Vec) -> Result<(CliConfig, CliCommand, Vec)> { let mut config = CliConfig::new()?; let mut command: Option = None; @@ -921,6 +915,55 @@ enum RecipeStatus { Failed(String), } +impl RecipeStatus { + pub fn fetch_is_part_of(&self) -> bool { + matches!(*self, RecipeStatus::Pending | RecipeStatus::Fetching) + } + pub fn fetch_style(&self) -> Style { + match *self { + RecipeStatus::Fetching => Style::default().fg(Color::Yellow), + _ => Style::default(), + } + } + pub fn fetch_icon(&self, spin: char) -> char { + match *self { + RecipeStatus::Pending => ' ', + RecipeStatus::Fetching => spin, + _ => '?', + } + } + pub fn cook_is_part_of(&self) -> bool { + matches!( + *self, + RecipeStatus::Fetched + | RecipeStatus::Cooking + | RecipeStatus::Done + | RecipeStatus::Cached + | RecipeStatus::Failed(_) + ) + } + pub fn cook_style(&self) -> Style { + match *self { + RecipeStatus::Fetched => Style::default(), + RecipeStatus::Cooking => Style::default().fg(Color::Yellow), + RecipeStatus::Done => Style::default().fg(Color::Green), + RecipeStatus::Cached => Style::default().fg(Color::Cyan), + RecipeStatus::Failed(_) => Style::default().fg(Color::Red), + _ => Style::default(), + } + } + pub fn cook_icon(&self, spin: char) -> char { + match *self { + RecipeStatus::Fetched => ' ', + RecipeStatus::Cooking => spin, + RecipeStatus::Done => '+', + RecipeStatus::Cached => ' ', + RecipeStatus::Failed(_) => 'X', + _ => '?', + } + } +} + #[derive(Debug, Clone, PartialEq)] enum StatusUpdate { StartFetch(PackageName), @@ -1363,20 +1406,10 @@ fn run_tui_cook(config: CliConfig, recipes: Vec) -> Result { let fetch_items: Vec = app .recipes .iter() - .filter(|(_, s)| *s == RecipeStatus::Pending || *s == RecipeStatus::Fetching) + .filter(|(_, s)| s.fetch_is_part_of()) .map(|(r, s)| { - let style = if *s == RecipeStatus::Fetching { - Style::default().fg(Color::Yellow) - } else { - Style::default() - }; - let icon = match s { - RecipeStatus::Pending => ' ', - RecipeStatus::Fetching => spin, - _ => '?', - }; - - ListItem::new(format!("{icon} {}", r.name)).style(style) + let icon = s.fetch_icon(spin); + ListItem::new(format!("{icon} {}", r.name)).style(s.fetch_style()) }) .collect(); let fetch_list = List::new(fetch_items).block( @@ -1390,43 +1423,17 @@ fn run_tui_cook(config: CliConfig, recipes: Vec) -> Result { let cook_items: Vec = app .recipes .iter() - .filter(|(_, s)| { - *s == RecipeStatus::Fetched - || *s == RecipeStatus::Cooking - || *s == RecipeStatus::Done - || *s == RecipeStatus::Cached - || matches!(s, RecipeStatus::Failed(_)) - }) + .filter(|(_, s)| s.cook_is_part_of()) .map(|(r, s)| { - let style = match s { - RecipeStatus::Fetched => Style::default(), - RecipeStatus::Cooking => Style::default().fg(Color::Yellow), - RecipeStatus::Done => Style::default().fg(Color::Green), - RecipeStatus::Cached => Style::default().fg(Color::Cyan), - RecipeStatus::Failed(_) => Style::default().fg(Color::Red), - _ => Style::default(), - }; - let icon = match s { - RecipeStatus::Fetched => ' ', - RecipeStatus::Cooking => spin, - RecipeStatus::Done => '+', - RecipeStatus::Cached => ' ', - RecipeStatus::Failed(_) => 'X', - _ => '?', - }; - ListItem::new(format!("{icon} {}", r.name)).style(style) + let icon = s.cook_icon(spin); + ListItem::new(format!("{icon} {}", r.name)).style(s.cook_style()) }) .collect(); { let cooking_index = app .recipes .iter() - .filter(|(_, s)| { - *s == RecipeStatus::Fetched - || *s == RecipeStatus::Cooking - || *s == RecipeStatus::Done - || matches!(s, RecipeStatus::Failed(_)) - }) + .filter(|(_, s)| s.cook_is_part_of()) .position(|(_r, s)| *s == RecipeStatus::Cooking); if let Some(index) = cooking_index { @@ -1852,3 +1859,11 @@ impl FailurePrompt { } } } + +macro_rules! bail_options_err { + ($($arg:tt)*) => { + return Err(cookbook::Error::Options(format!($($arg)*))) + }; +} + +use bail_options_err;