more review stuff

This commit is contained in:
steven-omaha
2023-01-19 13:31:55 +01:00
parent 1e5517a129
commit 6d852305c9
4 changed files with 137 additions and 98 deletions
+4
View File
@@ -67,6 +67,10 @@ impl Backend for Pacman {
cmd.status() cmd.status()
.with_context(|| format!("running command [{cmd:?}]")) .with_context(|| format!("running command [{cmd:?}]"))
} }
fn supports_assigning_packages_as_dependency(&self) -> bool {
true
}
} }
fn get_all_installed_packages_from_alpm() -> Result<HashSet<String>> { fn get_all_installed_packages_from_alpm() -> Result<HashSet<String>> {
+4
View File
@@ -31,6 +31,10 @@ impl Backend for Rust {
self.get_all_installed_packages() self.get_all_installed_packages()
.context("getting all installed packages") .context("getting all installed packages")
} }
fn supports_assigning_packages_as_dependency(&self) -> bool {
false
}
} }
fn extract_packages(json: Value) -> Result<HashSet<Package>> { fn extract_packages(json: Value) -> Result<HashSet<Package>> {
+2
View File
@@ -33,6 +33,8 @@ pub(crate) trait Backend {
.with_context(|| format!("running command {cmd:?}")) .with_context(|| format!("running command {cmd:?}"))
} }
fn supports_assigning_packages_as_dependency(&self) -> bool;
/// Remove the specified packages. /// Remove the specified packages.
fn remove_packages(&self, packages: &[Package]) -> Result<ExitStatus> { fn remove_packages(&self, packages: &[Package]) -> Result<ExitStatus> {
let mut cmd = Command::new(self.get_binary()); let mut cmd = Command::new(self.get_binary());
+128 -99
View File
@@ -7,6 +7,7 @@ use termios::*;
use crate::backend::{Backend, Backends, ToDoPerBackend}; use crate::backend::{Backend, Backends, ToDoPerBackend};
use crate::grouping::{Group, Package, Section}; use crate::grouping::{Group, Package, Section};
use crate::ui::get_user_confirmation;
#[derive(Debug)] #[derive(Debug)]
enum ReviewAction { enum ReviewAction {
@@ -19,23 +20,80 @@ enum ReviewAction {
Quit, Quit,
} }
struct Reviews<'a> { struct Reviews {
pub delete: Vec<(Rc<Box<dyn Backend>>, Package)>, pub delete: Vec<Delete>,
pub assign: Vec<(Rc<Box<dyn Backend>>, Package, &'a Group, &'a Section)>, pub assign: Vec<Assign>,
pub as_dependency: Vec<AsDependency>,
} }
impl<'a> Reviews<'a> { struct AsDependency {
backend: Rc<Box<dyn Backend>>,
package: Package,
}
impl AsDependency {
fn new(backend: Rc<Box<dyn Backend>>, package: Package) -> Self {
Self { backend, package }
}
}
struct Assign {
backend: Rc<Box<dyn Backend>>,
package: Package,
group: Rc<Group>,
}
impl Assign {
fn new(backend: Rc<Box<dyn Backend>>, package: Package, group: Rc<Group>) -> Self {
Self {
backend,
package,
group,
}
}
}
struct Delete {
items: Vec<>
backend: Rc<Box<dyn Backend>>,
package: Package,
}
impl Delete {
fn new(backend: Rc<Box<dyn Backend>>, package: Package) -> Self {
Self { backend, package }
}
}
impl Reviews {
fn new() -> Self { fn new() -> Self {
Self { Self {
delete: vec![], delete: vec![],
assign: 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<Group>) -> Result<()> { pub(crate) fn review(todo_per_backend: ToDoPerBackend, groups: HashSet<Group>) -> Result<()> {
let mut reviews = Reviews::new(); 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(); groups.sort_unstable();
if todo_per_backend.nothing_to_do_for_all_backends() { if todo_per_backend.nothing_to_do_for_all_backends() {
@@ -43,110 +101,87 @@ pub(crate) fn review(todo_per_backend: ToDoPerBackend, groups: HashSet<Group>) -
return Ok(()); 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<Rc<Group>>,
reviews: &mut Reviews,
) -> Result<()> {
for (backend, packages) in todo_per_backend.into_iter() { for (backend, packages) in todo_per_backend.into_iter() {
let backend = Rc::new(backend); let backend = Rc::new(backend);
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, reviews, &backend)?;
} }
} }
Ok(())
todo!()
} }
fn get_action_for_package( fn get_action_for_package(
package: Package, package: Package,
groups: &[Group], groups: &[Rc<Group>],
reviews: &mut Reviews, reviews: &mut Reviews,
backend: &Rc<Box<dyn Backend>>, backend: &Rc<Box<dyn Backend>>,
) -> Result<()> { ) -> Result<()> {
todo!(); loop {
// loop { match ask_user_action_for_package(backend)? {
// match ask_user_action_for_package()? { ReviewAction::AsDependency => {
// ReviewAction::AsDependency => todo!(), let as_dependency = AsDependency::new(backend.clone(), package);
// ReviewAction::AssignGroupBackend => { reviews.as_dependency.push(as_dependency);
// if let Some(val) = assign_group_backend(&package, groups)? { break;
// break; }
// }; ReviewAction::AssignGroupBackend => {
// } if let Some(group) = assign_group(groups)? {
// ReviewAction::Delete => { let assign = Assign::new(backend.clone(), package, group);
// reviews.delete.push((backend.clone(), package)); reviews.assign.push(assign);
// break; break;
// } };
// ReviewAction::Info => backend.show_package_info(&package)?, }
// ReviewAction::Invalid => (), ReviewAction::Delete => {
// ReviewAction::Skip => break, let delete = Delete::new(backend.clone(), package);
// ReviewAction::Quit => bail!("user wants to quit"), 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(()) Ok(())
} }
fn ask_user_group_section(groups: &[Group]) -> Result<Option<GroupSectionReply>> { fn ask_user_action_for_package(backend: &Rc<Box<dyn Backend>>) -> Result<ReviewAction> {
let group = match ask_group(groups)? { if backend.supports_assigning_packages_as_dependency() {
Some(group) => group, ask_action_including_dependency()
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<Section>) -> Result<Option<SectionReply>> {
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
} else { } else {
return Ok(None); ask_action_without_dependency()
};
if idx < sections.len() {
Ok(Some(SectionReply::Existing(&sections[idx])))
} else if idx == sections.len() {
Ok(Some(SectionReply::New))
} else {
Ok(None)
} }
} }
fn ask_new_section_name() -> Result<String> { fn ask_action_without_dependency() -> Result<ReviewAction> {
print!("new section name: "); print!("assign to (g)roup, (d)elete, (s)kip, (i)nfo, (q)uit? ");
let reply = stdin().lines().next().context("reading line from stdin")?; match read_single_char_from_terminal()? {
reply.map_err(|e| anyhow!(e)) 'd' => Ok(ReviewAction::Delete),
'g' => Ok(ReviewAction::AssignGroupBackend),
'i' => Ok(ReviewAction::Info),
'q' => Ok(ReviewAction::Quit),
's' => Ok(ReviewAction::Skip),
_ => Ok(ReviewAction::Invalid),
}
} }
fn print_enumerated_sections(sections: &[Section]) { fn ask_action_including_dependency() -> Result<ReviewAction> {
for (i, section) in sections.iter().enumerate() {
println!("{i}: {}", section.name);
}
println!("{}: [new]", sections.len());
}
fn ask_user_action_for_package() -> Result<ReviewAction> {
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? ");
match read_single_char_from_terminal()? { match read_single_char_from_terminal()? {
'a' => Ok(ReviewAction::AsDependency), 'a' => Ok(ReviewAction::AsDependency),
@@ -177,14 +212,13 @@ fn read_single_char_from_terminal() -> Result<char> {
Ok(result) Ok(result)
} }
fn print_enumerated_groups(groups: &[Group]) { fn print_enumerated_groups(groups: &[Rc<Group>]) {
for (i, group) in groups.iter().enumerate() { for (i, group) in groups.iter().enumerate() {
println!("{i}: {}", group.name); println!("{i}: {}", group.name);
} }
} }
fn ask_group(groups: &[Group]) -> Result<Option<&Group>> { fn ask_group(groups: &[Rc<Group>]) -> Result<Option<Rc<Group>>> {
print_enumerated_groups(groups);
let mut buf = String::new(); let mut buf = String::new();
stdin().read_line(&mut buf)?; stdin().read_line(&mut buf)?;
let reply = buf.trim(); let reply = buf.trim();
@@ -196,18 +230,13 @@ fn ask_group(groups: &[Group]) -> Result<Option<&Group>> {
}; };
if idx < groups.len() { if idx < groups.len() {
Ok(Some(&groups[idx])) Ok(Some(groups[idx].clone()))
} else { } else {
Ok(None) Ok(None)
} }
} }
fn assign_group_backend(package: &Package, groups: &[Group]) -> Result<()> { fn assign_group(groups: &[Rc<Group>]) -> Result<Option<Rc<Group>>> {
let reply = ask_user_group_section(groups)?; print_enumerated_groups(groups);
match reply { ask_group(groups)
Some(val) => todo!(),
None => todo!(),
}
todo!()
} }