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()
.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>> {
+4
View File
@@ -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<HashSet<Package>> {
+2
View File
@@ -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<ExitStatus> {
let mut cmd = Command::new(self.get_binary());
+127 -98
View File
@@ -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<Box<dyn Backend>>, Package)>,
pub assign: Vec<(Rc<Box<dyn Backend>>, Package, &'a Group, &'a Section)>,
struct Reviews {
pub delete: Vec<Delete>,
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 {
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<Group>) -> 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<Group>) -
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() {
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<Group>],
reviews: &mut Reviews,
backend: &Rc<Box<dyn Backend>>,
) -> 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<Option<GroupSectionReply>> {
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<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
fn ask_user_action_for_package(backend: &Rc<Box<dyn Backend>>) -> Result<ReviewAction> {
if backend.supports_assigning_packages_as_dependency() {
ask_action_including_dependency()
} else {
return Ok(None);
};
if idx < sections.len() {
Ok(Some(SectionReply::Existing(&sections[idx])))
} else if idx == sections.len() {
Ok(Some(SectionReply::New))
} else {
Ok(None)
ask_action_without_dependency()
}
}
fn ask_new_section_name() -> Result<String> {
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<ReviewAction> {
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<ReviewAction> {
fn ask_action_including_dependency() -> Result<ReviewAction> {
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<char> {
Ok(result)
}
fn print_enumerated_groups(groups: &[Group]) {
fn print_enumerated_groups(groups: &[Rc<Group>]) {
for (i, group) in groups.iter().enumerate() {
println!("{i}: {}", group.name);
}
}
fn ask_group(groups: &[Group]) -> Result<Option<&Group>> {
print_enumerated_groups(groups);
fn ask_group(groups: &[Rc<Group>]) -> Result<Option<Rc<Group>>> {
let mut buf = String::new();
stdin().read_line(&mut buf)?;
let reply = buf.trim();
@@ -196,18 +230,13 @@ fn ask_group(groups: &[Group]) -> Result<Option<&Group>> {
};
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<Group>]) -> Result<Option<Rc<Group>>> {
print_enumerated_groups(groups);
ask_group(groups)
}