From 6d852305c9a0c54def599d86ccb713d2f0d6b9d4 Mon Sep 17 00:00:00 2001 From: steven-omaha <35634100+steven-omaha@users.noreply.github.com> Date: Thu, 19 Jan 2023 13:31:55 +0100 Subject: [PATCH] more review stuff --- src/backend/actual/pacman.rs | 4 + src/backend/actual/rust.rs | 4 + src/backend/backend_trait.rs | 2 + src/review.rs | 225 ++++++++++++++++++++--------------- 4 files changed, 137 insertions(+), 98 deletions(-) diff --git a/src/backend/actual/pacman.rs b/src/backend/actual/pacman.rs index 36afe6d..f8a8344 100644 --- a/src/backend/actual/pacman.rs +++ b/src/backend/actual/pacman.rs @@ -67,6 +67,10 @@ impl Backend for Pacman { cmd.status() .with_context(|| format!("running command [{cmd:?}]")) } + + fn supports_assigning_packages_as_dependency(&self) -> bool { + true + } } fn get_all_installed_packages_from_alpm() -> Result> { diff --git a/src/backend/actual/rust.rs b/src/backend/actual/rust.rs index b4317c5..706d909 100644 --- a/src/backend/actual/rust.rs +++ b/src/backend/actual/rust.rs @@ -31,6 +31,10 @@ impl Backend for Rust { self.get_all_installed_packages() .context("getting all installed packages") } + + fn supports_assigning_packages_as_dependency(&self) -> bool { + false + } } fn extract_packages(json: Value) -> Result> { diff --git a/src/backend/backend_trait.rs b/src/backend/backend_trait.rs index 6376d92..d375de5 100644 --- a/src/backend/backend_trait.rs +++ b/src/backend/backend_trait.rs @@ -33,6 +33,8 @@ pub(crate) trait Backend { .with_context(|| format!("running command {cmd:?}")) } + fn supports_assigning_packages_as_dependency(&self) -> bool; + /// Remove the specified packages. fn remove_packages(&self, packages: &[Package]) -> Result { let mut cmd = Command::new(self.get_binary()); diff --git a/src/review.rs b/src/review.rs index d94274d..e28998e 100644 --- a/src/review.rs +++ b/src/review.rs @@ -7,6 +7,7 @@ use termios::*; use crate::backend::{Backend, Backends, ToDoPerBackend}; use crate::grouping::{Group, Package, Section}; +use crate::ui::get_user_confirmation; #[derive(Debug)] enum ReviewAction { @@ -19,23 +20,80 @@ enum ReviewAction { Quit, } -struct Reviews<'a> { - pub delete: Vec<(Rc>, Package)>, - pub assign: Vec<(Rc>, Package, &'a Group, &'a Section)>, +struct Reviews { + pub delete: Vec, + pub assign: Vec, + pub as_dependency: Vec, } -impl<'a> Reviews<'a> { +struct AsDependency { + backend: Rc>, + package: Package, +} + +impl AsDependency { + fn new(backend: Rc>, package: Package) -> Self { + Self { backend, package } + } +} + +struct Assign { + backend: Rc>, + package: Package, + group: Rc, +} + +impl Assign { + fn new(backend: Rc>, package: Package, group: Rc) -> Self { + Self { + backend, + package, + group, + } + } +} + +struct Delete { + items: Vec<> + backend: Rc>, + package: Package, +} + +impl Delete { + fn new(backend: Rc>, package: Package) -> Self { + Self { backend, package } + } +} + +impl Reviews { fn new() -> Self { Self { delete: vec![], assign: vec![], + as_dependency: vec![], } } + + fn show_strategy(&mut self) { + self.delete + .sort_by_key(|d| (&d.backend.get_section(), &d.package)); + if !self.delete.is_empty() { + println!("Will delete the following packages:"); + let mut iter = self.delete.iter().peekable(); + // while let Some(delete) = iter.next() { + // delete. + // } + } + } + + fn execute(&self) -> Result<()> { + todo!() + } } pub(crate) fn review(todo_per_backend: ToDoPerBackend, groups: HashSet) -> Result<()> { let mut reviews = Reviews::new(); - let mut groups: Vec<_> = groups.into_iter().collect(); + let mut groups: Vec<_> = groups.into_iter().map(Rc::new).collect(); groups.sort_unstable(); if todo_per_backend.nothing_to_do_for_all_backends() { @@ -43,110 +101,87 @@ pub(crate) fn review(todo_per_backend: ToDoPerBackend, groups: HashSet) - return Ok(()); } + gather_reviews(todo_per_backend, groups, &mut reviews)?; + + reviews.show_strategy(); + + if !get_user_confirmation() { + return Ok(()); + } + + reviews.execute() +} + +fn gather_reviews( + todo_per_backend: ToDoPerBackend, + groups: Vec>, + reviews: &mut Reviews, +) -> Result<()> { for (backend, packages) in todo_per_backend.into_iter() { let backend = Rc::new(backend); for package in packages { println!("{}: {package}", backend.get_section()); - get_action_for_package(package, &groups, &mut reviews, &backend)?; + get_action_for_package(package, &groups, reviews, &backend)?; } } - - todo!() + Ok(()) } fn get_action_for_package( package: Package, - groups: &[Group], + groups: &[Rc], reviews: &mut Reviews, backend: &Rc>, ) -> Result<()> { - todo!(); - // loop { - // match ask_user_action_for_package()? { - // ReviewAction::AsDependency => todo!(), - // ReviewAction::AssignGroupBackend => { - // if let Some(val) = assign_group_backend(&package, groups)? { - // break; - // }; - // } - // ReviewAction::Delete => { - // reviews.delete.push((backend.clone(), package)); - // break; - // } - // ReviewAction::Info => backend.show_package_info(&package)?, - // ReviewAction::Invalid => (), - // ReviewAction::Skip => break, - // ReviewAction::Quit => bail!("user wants to quit"), - // } - // } + loop { + match ask_user_action_for_package(backend)? { + ReviewAction::AsDependency => { + let as_dependency = AsDependency::new(backend.clone(), package); + reviews.as_dependency.push(as_dependency); + break; + } + ReviewAction::AssignGroupBackend => { + if let Some(group) = assign_group(groups)? { + let assign = Assign::new(backend.clone(), package, group); + reviews.assign.push(assign); + break; + }; + } + ReviewAction::Delete => { + let delete = Delete::new(backend.clone(), package); + reviews.delete.push(delete); + break; + } + ReviewAction::Info => backend.show_package_info(&package)?, + ReviewAction::Invalid => (), + ReviewAction::Skip => break, + ReviewAction::Quit => bail!("user wants to quit"), // TODO requires an own error type? + } + } Ok(()) } -fn ask_user_group_section(groups: &[Group]) -> Result> { - let group = match ask_group(groups)? { - Some(group) => group, - None => return Ok(None), - }; - - let section_reply = match ask_section(&group.sections)? { - Some(reply) => reply, - None => return Ok(None), - }; - - let section = match section_reply { - SectionReply::Existing(section) => section, - SectionReply::New => return Ok(Some(GroupSectionReply::New)), - }; - - Ok(Some(GroupSectionReply::Existing((group, section)))) -} - -enum GroupSectionReply<'a> { - Existing((&'a Group, &'a Section)), - New, -} - -enum SectionReply<'a> { - Existing(&'a Section), - New, -} - -fn ask_section(sections: &HashSet
) -> Result> { - let sections: Vec<_> = sections.iter().collect(); - - let mut buf = String::new(); - stdin().read_line(&mut buf)?; - let reply = buf.trim(); - - let idx: usize = if let Ok(idx) = reply.parse() { - idx +fn ask_user_action_for_package(backend: &Rc>) -> Result { + if backend.supports_assigning_packages_as_dependency() { + ask_action_including_dependency() } else { - return Ok(None); - }; - - if idx < sections.len() { - Ok(Some(SectionReply::Existing(§ions[idx]))) - } else if idx == sections.len() { - Ok(Some(SectionReply::New)) - } else { - Ok(None) + ask_action_without_dependency() } } -fn ask_new_section_name() -> Result { - print!("new section name: "); - let reply = stdin().lines().next().context("reading line from stdin")?; - reply.map_err(|e| anyhow!(e)) -} - -fn print_enumerated_sections(sections: &[Section]) { - for (i, section) in sections.iter().enumerate() { - println!("{i}: {}", section.name); +fn ask_action_without_dependency() -> Result { + print!("assign to (g)roup, (d)elete, (s)kip, (i)nfo, (q)uit? "); + match read_single_char_from_terminal()? { + 'd' => Ok(ReviewAction::Delete), + 'g' => Ok(ReviewAction::AssignGroupBackend), + 'i' => Ok(ReviewAction::Info), + 'q' => Ok(ReviewAction::Quit), + 's' => Ok(ReviewAction::Skip), + _ => Ok(ReviewAction::Invalid), } - println!("{}: [new]", sections.len()); } -fn ask_user_action_for_package() -> Result { +fn ask_action_including_dependency() -> Result { print!("assign to (g)roup, (d)elete, (s)kip, (i)nfo, (a)s dependency, (q)uit? "); match read_single_char_from_terminal()? { 'a' => Ok(ReviewAction::AsDependency), @@ -177,14 +212,13 @@ fn read_single_char_from_terminal() -> Result { Ok(result) } -fn print_enumerated_groups(groups: &[Group]) { +fn print_enumerated_groups(groups: &[Rc]) { for (i, group) in groups.iter().enumerate() { println!("{i}: {}", group.name); } } -fn ask_group(groups: &[Group]) -> Result> { - print_enumerated_groups(groups); +fn ask_group(groups: &[Rc]) -> Result>> { let mut buf = String::new(); stdin().read_line(&mut buf)?; let reply = buf.trim(); @@ -196,18 +230,13 @@ fn ask_group(groups: &[Group]) -> Result> { }; if idx < groups.len() { - Ok(Some(&groups[idx])) + Ok(Some(groups[idx].clone())) } else { Ok(None) } } -fn assign_group_backend(package: &Package, groups: &[Group]) -> Result<()> { - let reply = ask_user_group_section(groups)?; - match reply { - Some(val) => todo!(), - None => todo!(), - } - - todo!() +fn assign_group(groups: &[Rc]) -> Result>> { + print_enumerated_groups(groups); + ask_group(groups) }