start adding review
This commit is contained in:
Generated
+10
@@ -152,6 +152,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"termios",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -295,6 +296,15 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termios"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ serde_yaml = "*"
|
|||||||
serde_derive = "*"
|
serde_derive = "*"
|
||||||
serde = "*"
|
serde = "*"
|
||||||
pacdef_macro = {path = "pacdef_macro/"}
|
pacdef_macro = {path = "pacdef_macro/"}
|
||||||
|
termios = "*"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "off"
|
lto = "off"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ pub(crate) enum Actions {
|
|||||||
Import,
|
Import,
|
||||||
New,
|
New,
|
||||||
Remove,
|
Remove,
|
||||||
|
Review,
|
||||||
Search,
|
Search,
|
||||||
Show,
|
Show,
|
||||||
Sync,
|
Sync,
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ fn get_arg_parser() -> Command<'static> {
|
|||||||
.arg_required_else_help(true)
|
.arg_required_else_help(true)
|
||||||
.arg(Arg::new("groups").multiple_values(true)),
|
.arg(Arg::new("groups").multiple_values(true)),
|
||||||
)
|
)
|
||||||
|
.subcommand(Command::new(REVIEW).about("review unmanaged packages"))
|
||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new(SEARCH)
|
Command::new(SEARCH)
|
||||||
.about("search for packages which match a provided string literal or regex")
|
.about("search for packages which match a provided string literal or regex")
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ pub(crate) trait Backend {
|
|||||||
|
|
||||||
fn add_packages(&mut self, packages: HashSet<Package>);
|
fn add_packages(&mut self, packages: HashSet<Package>);
|
||||||
|
|
||||||
|
fn show_package_info(&self, package: &Package) -> Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn get_unmanaged_packages_sorted(&self) -> Result<Vec<Package>> {
|
fn get_unmanaged_packages_sorted(&self) -> Result<Vec<Package>> {
|
||||||
let installed = self
|
let installed = self
|
||||||
.get_explicitly_installed_packages()
|
.get_explicitly_installed_packages()
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ impl ToDoPerBackend {
|
|||||||
self.0.push(item);
|
self.0.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn into_iter(self) -> impl Iterator<Item = (Box<dyn Backend>, Vec<Package>)> {
|
||||||
|
self.0.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &(Box<dyn Backend>, Vec<Package>)> {
|
pub(crate) fn iter(&self) -> impl Iterator<Item = &(Box<dyn Backend>, Vec<Package>)> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -12,6 +12,7 @@ use crate::backend::{Backend, Backends, ToDoPerBackend};
|
|||||||
use crate::cmd::run_edit_command;
|
use crate::cmd::run_edit_command;
|
||||||
use crate::env::get_single_var;
|
use crate::env::get_single_var;
|
||||||
use crate::path::get_pacdef_group_dir;
|
use crate::path::get_pacdef_group_dir;
|
||||||
|
use crate::review;
|
||||||
use crate::search;
|
use crate::search;
|
||||||
use crate::ui::get_user_confirmation;
|
use crate::ui::get_user_confirmation;
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
@@ -43,6 +44,8 @@ impl Pacdef {
|
|||||||
Some((IMPORT, args)) => self.import_groups(args).context("importing groups"),
|
Some((IMPORT, args)) => self.import_groups(args).context("importing groups"),
|
||||||
Some((NEW, args)) => self.new_groups(args).context("creating new group files"),
|
Some((NEW, args)) => self.new_groups(args).context("creating new group files"),
|
||||||
Some((REMOVE, args)) => self.remove_groups(args).context("removing groups"),
|
Some((REMOVE, args)) => self.remove_groups(args).context("removing groups"),
|
||||||
|
Some((REVIEW, _)) => review::review(self.get_unmanaged_packages(), self.groups)
|
||||||
|
.context("removing groups"),
|
||||||
Some((SHOW, args)) => self.show_group_content(args).context("showing groups"),
|
Some((SHOW, args)) => self.show_group_content(args).context("showing groups"),
|
||||||
Some((SEARCH, args)) => {
|
Some((SEARCH, args)) => {
|
||||||
search::search_packages(args, &self.groups).context("searching packages")
|
search::search_packages(args, &self.groups).context("searching packages")
|
||||||
@@ -141,7 +144,7 @@ impl Pacdef {
|
|||||||
unmanaged_per_backend.show(None);
|
unmanaged_per_backend.show(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_unmanaged_packages(self) -> ToDoPerBackend {
|
fn get_unmanaged_packages(&self) -> ToDoPerBackend {
|
||||||
let mut result = ToDoPerBackend::new();
|
let mut result = ToDoPerBackend::new();
|
||||||
|
|
||||||
for backend in Backends::iter() {
|
for backend in Backends::iter() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ mod core;
|
|||||||
mod env;
|
mod env;
|
||||||
mod grouping;
|
mod grouping;
|
||||||
mod path;
|
mod path;
|
||||||
|
mod review;
|
||||||
mod search;
|
mod search;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
|||||||
+142
@@ -0,0 +1,142 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
use std::io::{self, stdin, Read};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
use termios::*;
|
||||||
|
|
||||||
|
use crate::backend::{Backend, Backends, ToDoPerBackend};
|
||||||
|
use crate::grouping::{Group, Package, Section};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ReviewAction {
|
||||||
|
AsDependency,
|
||||||
|
AssignGroupBackend,
|
||||||
|
Delete,
|
||||||
|
Info,
|
||||||
|
Invalid,
|
||||||
|
Skip,
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Reviews<'a> {
|
||||||
|
pub delete: Vec<(Rc<Box<dyn Backend>>, Package)>,
|
||||||
|
pub assign: Vec<(Rc<Box<dyn Backend>>, Package, &'a Group, &'a Section)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reviews {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
delete: vec![],
|
||||||
|
assign: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
groups.sort_unstable();
|
||||||
|
|
||||||
|
if todo_per_backend.nothing_to_do_for_all_backends() {
|
||||||
|
println!("nothing to do");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (backend, packages) in todo_per_backend.into_iter() {
|
||||||
|
let backend = Rc::new(backend);
|
||||||
|
for package in packages {
|
||||||
|
println!("{}: {package}", backend.get_section());
|
||||||
|
'inner: loop {
|
||||||
|
match ask_user_action_for_package()? {
|
||||||
|
ReviewAction::AsDependency => todo!(),
|
||||||
|
ReviewAction::AssignGroupBackend => {
|
||||||
|
if let Some((group, section)) = ask_user_group_section(&package, &groups)? {
|
||||||
|
reviews
|
||||||
|
.assign
|
||||||
|
.push((backend.clone(), package, &group, §ion));
|
||||||
|
break 'inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReviewAction::Delete => {
|
||||||
|
reviews.delete.push((backend.clone(), package));
|
||||||
|
break 'inner;
|
||||||
|
}
|
||||||
|
ReviewAction::Info => backend.show_package_info(&package)?,
|
||||||
|
ReviewAction::Invalid => (),
|
||||||
|
ReviewAction::Skip => break 'inner,
|
||||||
|
ReviewAction::Quit => bail!("user wants to quit"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ask_user_group_section<'a>(
|
||||||
|
package: &'a Package,
|
||||||
|
groups: &'a [Group],
|
||||||
|
) -> Result<Option<(&'a Group, &'a Section)>> {
|
||||||
|
if let Some(group) = ask_group(groups)? {
|
||||||
|
if let Some(section) = ask_section(section)? {
|
||||||
|
return Ok(Some((group, section)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ask_user_action_for_package() -> 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),
|
||||||
|
'd' => Ok(ReviewAction::Delete),
|
||||||
|
'g' => Ok(ReviewAction::AssignGroupBackend),
|
||||||
|
'i' => Ok(ReviewAction::Info),
|
||||||
|
'q' => Ok(ReviewAction::Quit),
|
||||||
|
's' => Ok(ReviewAction::Skip),
|
||||||
|
_ => Ok(ReviewAction::Invalid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_single_char_from_terminal() -> Result<char> {
|
||||||
|
let fd = 0; // 0 is the file descriptor for stdin
|
||||||
|
let termios = Termios::from_fd(fd)?;
|
||||||
|
let mut new_termios = termios;
|
||||||
|
new_termios.c_lflag &= !(ICANON | ECHO);
|
||||||
|
new_termios.c_cc[VMIN] = 1;
|
||||||
|
new_termios.c_cc[VTIME] = 0;
|
||||||
|
tcsetattr(fd, TCSANOW, &new_termios).unwrap();
|
||||||
|
|
||||||
|
let mut input = [0u8; 1];
|
||||||
|
io::stdin().read_exact(&mut input[..]).unwrap();
|
||||||
|
let result = input[0] as char;
|
||||||
|
println!("{result}");
|
||||||
|
|
||||||
|
tcsetattr(fd, TCSANOW, &termios).unwrap(); // restore previous settings
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_enumerated_groups(groups: &[Group]) {
|
||||||
|
for (i, group) in groups.iter().enumerate() {
|
||||||
|
println!("{i}: {}", group.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ask_group(groups: &[Group]) -> Result<Option<&Group>> {
|
||||||
|
print_enumerated_groups(groups);
|
||||||
|
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 {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
if idx < groups.len() {
|
||||||
|
Ok(Some(&groups[idx]))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user