even more review stuff

This commit is contained in:
steven-omaha
2023-01-31 15:25:24 +01:00
parent 1b3f0f9781
commit 000ad413db
+164 -110
View File
@@ -1,55 +1,17 @@
use std::collections::{HashMap, HashSet};
use std::io::{self, stdin, stdout, Read, Write}; use std::io::{self, stdin, stdout, Read, Write};
use std::rc::Rc;
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{bail, Result};
use termios::*; use termios::*;
use crate::backend::{Backend, Backends, ToDoPerBackend}; use crate::backend::{Backend, ToDoPerBackend};
use crate::grouping::{Group, Package, Section}; use crate::grouping::{Group, Package};
use crate::ui::get_user_confirmation; use crate::ui::get_user_confirmation;
#[derive(Debug)] #[derive(Debug)]
struct BackendVectorMap<I>(Vec<(Rc<Box<dyn Backend>>, Vec<I>)>); struct ReviewsPerBackend<'a>(Vec<(Box<dyn Backend>, Vec<ReviewAction<'a>>)>);
impl<I> BackendVectorMap<I> {
fn new() -> Self {
Self(vec![])
}
fn get(&self, backend: &Rc<Box<dyn Backend>>) -> Option<&[I]> {
for (b, value) in &self.0 {
if b.get_section() == backend.get_section() {
return Some(value);
}
}
return None;
}
fn get_mut(&mut self, backend: &Rc<Box<dyn Backend>>) -> Option<&mut [I]> {
for (b, value) in &mut self.0 {
if b.get_section() == backend.get_section() {
return Some(value);
}
}
return None;
}
fn push(&mut self, val: I) {
todo!()
}
fn is_empty(&self) -> bool {
self.0.iter().all(|(_, packages)| packages.is_empty())
}
fn iter(&self) -> impl Iterator<Item = &I> {
self.0.iter().flat_map(|(_, items)| items)
}
}
#[derive(Debug)] #[derive(Debug)]
enum ReviewAction { enum ReviewIntention {
AsDependency, AsDependency,
AssignGroup, AssignGroup,
Delete, Delete,
@@ -59,59 +21,30 @@ enum ReviewAction {
Quit, Quit,
} }
#[derive(Debug)] #[derive(Debug, PartialEq)]
struct Reviews<'a> { enum ReviewAction<'a> {
pub as_dependency: BackendVectorMap<Package>, AsDependency(Package),
pub assign: BackendVectorMap<(Package, &'a Group)>, Delete(Package),
pub delete: BackendVectorMap<Package>, AssignGroup(Package, &'a Group),
} }
impl<'a> Reviews<'a> { impl<'a> ReviewsPerBackend<'a> {
fn new() -> Self { fn new() -> Self {
Self { Self(vec![])
as_dependency: BackendVectorMap::new(),
assign: BackendVectorMap::new(),
delete: BackendVectorMap::new(),
}
}
// order will be: per backend, first assign, then delete, then as dependency
fn run_strategy(self) -> Result<()> {
todo!()
}
fn print_strategy(&self) {
println!("delete:");
if !self.delete.is_empty() {
for (backend, package) in self.delete.iter() {
println!("{} {}", backend.get_section(), package.name);
}
}
if !self.assign.is_empty() {
println!("assign:");
for (backend, package, group) in &self.assign {
println!("{} {} {}", backend.get_section(), package.name, group.name);
}
}
if !self.as_dependency.is_empty() {
println!("as dependency:");
for (backend, package) in &self.as_dependency {
println!("{} {}", backend.get_section(), package.name);
}
}
} }
pub(crate) fn nothing_to_do(&self) -> bool { pub(crate) fn nothing_to_do(&self) -> bool {
self.as_dependency.is_empty() && self.assign.is_empty() && self.delete.is_empty() self.0.iter().all(|(_, vec)| vec.is_empty())
} }
} }
pub(crate) fn review(todo_per_backend: ToDoPerBackend, groups: HashSet<Group>) -> Result<()> { pub(crate) fn review(
todo_per_backend: ToDoPerBackend,
groups: impl IntoIterator<Item = Group>,
) -> Result<()> {
dbg!(&todo_per_backend); dbg!(&todo_per_backend);
let mut reviews = Reviews::new(); let mut reviews = ReviewsPerBackend::new();
let mut groups: Vec<_> = groups.into_iter().collect(); let mut groups: Vec<_> = groups.into_iter().collect();
groups.sort_unstable(); groups.sort_unstable();
@@ -121,72 +54,72 @@ pub(crate) fn review(todo_per_backend: ToDoPerBackend, groups: HashSet<Group>) -
} }
for (backend, packages) in todo_per_backend.into_iter() { for (backend, packages) in todo_per_backend.into_iter() {
let backend = Rc::new(backend); let mut actions = vec![];
for package in packages { for package in packages {
println!("{}: {package}", backend.get_section()); println!("{}: {package}", backend.get_section());
get_action_for_package(package, &groups, &mut reviews, &backend)?; get_action_for_package(package, &groups, &mut actions, &*backend)?;
} }
reviews.0.push((backend, actions));
} }
if reviews.nothing_to_do() { if reviews.nothing_to_do() {
return Ok(()); return Ok(());
} }
reviews.print_strategy(); let strategy: Vec<Strategy> = reviews.into();
if !get_user_confirmation() { if !get_user_confirmation() {
return Ok(()); return Ok(());
} }
reviews.run_strategy() strategy.execute()
} }
fn get_action_for_package<'a>( fn get_action_for_package<'a>(
package: Package, package: Package,
groups: &'a [Group], groups: &'a [Group],
reviews: &mut Reviews<'a>, reviews: &mut Vec<ReviewAction<'a>>,
backend: &Rc<Box<dyn Backend>>, backend: &dyn Backend,
) -> Result<()> { ) -> Result<()> {
loop { loop {
match ask_user_action_for_package()? { match ask_user_action_for_package()? {
ReviewAction::AsDependency => { ReviewIntention::AsDependency => {
// reviews.as_dependency.insert(_); reviews.push(ReviewAction::AsDependency(package));
reviews.as_dependency.push((backend.clone(), package));
break; break;
} }
ReviewAction::AssignGroup => { ReviewIntention::AssignGroup => {
if let Ok(Some(group)) = ask_group(groups) { if let Ok(Some(group)) = ask_group(groups) {
reviews.assign.push((backend.clone(), package, group)); reviews.push(ReviewAction::AssignGroup(package, group));
break; break;
}; };
} }
ReviewAction::Delete => { ReviewIntention::Delete => {
reviews.delete.push((backend.clone(), package)); reviews.push(ReviewAction::Delete(package));
break; break;
} }
ReviewAction::Info => { ReviewIntention::Info => {
backend.show_package_info(&package)?; backend.show_package_info(&package)?;
} }
ReviewAction::Invalid => (), ReviewIntention::Invalid => (),
ReviewAction::Skip => break, ReviewIntention::Skip => break,
// TODO custom return type // TODO custom return type
ReviewAction::Quit => bail!("user wants to quit"), ReviewIntention::Quit => bail!("user wants to quit"),
} }
} }
Ok(()) Ok(())
} }
fn ask_user_action_for_package() -> Result<ReviewAction> { fn ask_user_action_for_package() -> Result<ReviewIntention> {
print!("assign to (g)roup, (d)elete, (s)kip, (i)nfo, (a)s dependency, (q)uit? "); print!("assign to (g)roup, (d)elete, (s)kip, (i)nfo, (a)s dependency, (q)uit? ");
stdout().lock().flush()?; stdout().lock().flush()?;
match read_single_char_from_terminal()? { match read_single_char_from_terminal()? {
'a' => Ok(ReviewAction::AsDependency), 'a' => Ok(ReviewIntention::AsDependency),
'd' => Ok(ReviewAction::Delete), 'd' => Ok(ReviewIntention::Delete),
'g' => Ok(ReviewAction::AssignGroup), 'g' => Ok(ReviewIntention::AssignGroup),
'i' => Ok(ReviewAction::Info), 'i' => Ok(ReviewIntention::Info),
'q' => Ok(ReviewAction::Quit), 'q' => Ok(ReviewIntention::Quit),
's' => Ok(ReviewAction::Skip), 's' => Ok(ReviewIntention::Skip),
_ => Ok(ReviewAction::Invalid), _ => Ok(ReviewIntention::Invalid),
} }
} }
@@ -232,3 +165,124 @@ fn ask_group(groups: &[Group]) -> Result<Option<&Group>> {
Ok(None) Ok(None)
} }
} }
#[derive(Debug)]
struct Strategy {
backend: Box<dyn Backend>,
delete: Vec<Package>,
as_dependency: Vec<Package>,
assign_group: Vec<(Package, Group)>,
}
impl Strategy {
fn new(
backend: Box<dyn Backend>,
delete: Vec<Package>,
as_dependency: Vec<Package>,
assign_group: Vec<(Package, Group)>,
) -> Self {
Self {
backend,
delete,
as_dependency,
assign_group,
}
}
fn get_assign_to_group<'a>(actions: &'a mut [ReviewAction<'a>]) -> Vec<(Package, Group)> {
let mut result: Vec<_> = actions
.iter()
.filter_map(|action| {
if let ReviewAction::AssignGroup(p, g) = action {
todo!()
// Some((*p, **g))
} else {
None
}
})
.collect();
result.sort();
result
}
fn get_make_dependency<'a>(actions: &'a mut [ReviewAction<'a>]) -> Vec<Package> {
let mut result: Vec<_> = actions
.iter()
.filter_map(|action| {
if let ReviewAction::AsDependency(p) = action {
todo!()
// Some(*p)
} else {
None
}
})
.collect();
result.sort();
result
}
fn get_to_delete<'a>(actions: &'a [ReviewAction<'a>]) -> Vec<&'a Package> {
let mut result: Vec<_> = actions
.iter()
.filter_map(|action| {
if let ReviewAction::Delete(p) = action {
Some(p)
} else {
None
}
})
.collect();
result.sort();
result
}
// fn print_strategy(&self) {
// for (backend, actions) in &self.0 {
// if actions.is_empty() {
// continue;
// }
// println!("[{}]", backend.get_section());
// let to_delete = get_to_delete(actions);
// let as_dependency = get_make_dependency(actions);
// let assign_group = get_assign_to_group(actions);
// if !to_delete.is_empty() {
// println!("delete:");
// for p in &to_delete {
// println!(" {p}");
// }
// }
// if !as_dependency.is_empty() {
// println!("as dependency:");
// for p in &as_dependency {
// println!(" {p}");
// }
// }
// if !assign_group.is_empty() {
// println!("assign group:");
// for &(p, g) in &assign_group {
// println!(" {p} -> {}", g.name);
// }
// }
// }
// }
//
fn execute(self) -> Result<()> {
todo!()
}
}
impl<'a> From<ReviewsPerBackend<'a>> for Vec<Strategy> {
fn from(reviews: ReviewsPerBackend) -> Self {
let mut result = vec![];
for (backend, actions) in reviews.0 {
let (to_delete, assign_group, as_dependency) = divide_actions(actions);
}
result
}
}