diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2020-02-29 22:23:55 +0100 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2020-06-01 13:58:54 +0200 |
commit | 779378bcf5a476c2f5fd4b86619c5d22c2e03b28 (patch) | |
tree | 173e31802db3033c2f05cb343ef78eff1fe95c52 | |
parent | 003826cbdf2f2fd8d2695cce73dbf6aba0a45b17 (diff) |
Reimplement imag-mail to take queries from stdin
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | bin/domain/imag-mail/src/lib.rs | 129 | ||||
-rw-r--r-- | bin/domain/imag-mail/src/ui.rs | 27 |
2 files changed, 40 insertions, 116 deletions
diff --git a/bin/domain/imag-mail/src/lib.rs b/bin/domain/imag-mail/src/lib.rs index 720f7a93..383a7ca8 100644 --- a/bin/domain/imag-mail/src/lib.rs +++ b/bin/domain/imag-mail/src/lib.rs @@ -51,21 +51,21 @@ extern crate libimagentryref; extern crate libimaginteraction; use std::io::Write; +use std::io::BufRead; use failure::Fallible as Result; use failure::err_msg; +use failure::Error; use clap::App; use resiter::AndThen; use resiter::IterInnerOkOrElse; use resiter::Filter; use resiter::Map; use handlebars::Handlebars; -use itertools::Itertools; use libimagmail::store::MailStore; use libimagmail::store::Sorting; use libimagmail::mail::Mail; -use libimagmail::store::MailStoreWithConnection; use libimagmail::notmuch::connection::NotmuchConnection; use libimagrt::runtime::Runtime; use libimagrt::application::ImagApplication; @@ -153,16 +153,13 @@ fn list(rt: &Runtime) -> Result<()> { let notmuch_connection = NotmuchConnection::open(notmuch_path)?; - let find_root = scmd.is_present("find-root"); - debug!("find_root: {}", find_root); - let mut out = rt.stdout(); let mut i = 0; /// Helper function for processing a tree /// /// This function implements the normal-style printing functionality (without "--tree"). - fn process_nontree<'a, I>(iter: I, + fn process<'a, I>(iter: I, i: &mut usize, conn: &NotmuchConnection, list_format: &Handlebars, @@ -171,7 +168,6 @@ fn list(rt: &Runtime) -> Result<()> { -> Result<()> where I: Iterator<Item = Result<FileLockEntry<'a>>> { - debug!("Processing non-tree"); iter.and_then_ok(|fle| { trace!("Loading: {}", fle.get_location()); let loaded = fle.load(&conn)? @@ -191,78 +187,6 @@ fn list(rt: &Runtime) -> Result<()> { .map(|_| ()) }; - /// Helper function for processing a tree - /// - /// This function implements the tree-style printing functionality ("--tree"). - fn process_tree<'a, I>(iter: I, - mailstore: &'a MailStoreWithConnection<'a>, - conn: &NotmuchConnection, - list_format: &Handlebars, - rt: &Runtime, - out: &mut dyn Write, - find_root: bool) - -> Result<()> - where I: Iterator<Item = Result<FileLockEntry<'a>>> - { - debug!("Processing tree"); - let iter = if find_root { - let iter = iter.and_then_ok(|fle| { - trace!("Loading: {}", fle.get_location()); - let id = fle - .load(conn)? - .ok_or_else(|| format_err!("Cannot load mail: {}", fle.get_location()))? - .parsed()? - .root_parent(&mailstore)? - .ok_or_else(|| format_err!("Failed to find root parent: {}", fle.get_location())) - .map(|p| p.get_id().clone()); - - drop(fle); - trace!("Loaded and parsed {:?} successfully", id); - id - }); - - Box::new(iter) as Box<dyn Iterator<Item = Result<String>>> - } else { - let iter = iter.and_then_ok(|fle| fle.get_cached_id()); - Box::new(iter) as Box<dyn Iterator<Item = Result<String>>> - }; - - trace!("Printing mailtrees now!"); - - // we have to collect here, so that all FLEs are drop()ed - let ids = iter.collect::<Result<Vec<String>>>()?; - trace!("ids = {:?}", ids); - - let mss = ids.into_iter() - .map(|id: String| mailstore.get_mailtree(&id)) - .collect::<Result<Vec<_>>>()?; - trace!("mss = {:?}", mss); - - mss.iter() - .map(|mailtree| mailtree.traverse()) - .flatten() - .unique_by(|tpl| tpl.1.clone()) - .sorted_by(|a, b| a.0.cmp(&b.0)) - .enumerate() - .map(|(i, (indent, mid))| { - let fle = mailstore.get_mail_by_id(&mid)?.ok_or_else(|| format_err!("Cannot find mail with id = {}", mid))?; - trace!("Printing: {}", fle.get_location()); - - let loaded = fle.load(&conn)? - .ok_or_else(|| format_err!("Mail not found: {}", fle.get_location()))?; - trace!("Loaded: {}", fle.get_location()); - - let parsed = loaded.parsed()?; - trace!("Parsed: {}", fle.get_location()); - - crate::util::list_mail(&parsed, i, indent, list_format, out)?; - trace!("Listed: {}", fle.get_location()); - rt.report_touched(fle.get_location()) - }) - .collect::<Result<Vec<()>>>() - .map(|_| ()) - } - if let Some(query) = scmd.value_of("query") { // Use notmuch to find mails @@ -276,28 +200,37 @@ fn list(rt: &Runtime) -> Result<()> { .into_iter() .map(Ok); - if tree { - process_tree(iter, &mailstore, ¬much_connection, &list_format, rt, &mut out, find_root) - } else { - process_nontree(iter, &mut i, ¬much_connection, &list_format, rt, &mut out) - } + process(iter, &mut i, ¬much_connection, &list_format, rt, &mut out) } else { - // use StoreIds to find mails - let iter = rt.ids::<crate::ui::PathProvider>()? - .ok_or_else(|| err_msg("No ids supplied"))? - .into_iter() - .map(Ok) - .into_get_iter(rt.store()) - .map_inner_ok_or_else(|| err_msg("Did not find one entry")) - .and_then_ok(|m| m.is_mail().map(|b| (b, m))) - .filter_ok(|tpl| tpl.0) - .map_ok(|tpl| tpl.1); - - if tree { + if scmd.is_present("query-from-stdin") { + let stdin = ::std::io::stdin(); + let mailstore = store.with_connection(¬much_connection); - process_tree(iter, &mailstore, ¬much_connection, &list_format, rt, &mut out, find_root) + stdin.lock() + .lines() + .map(|r| r.map_err(Error::from).and_then(|query| { + debug!("Querying: {}", query); + let it = mailstore.query(&query)?; + + debug!("Found: {:?}", it); + let it = it.into_iter().map(Ok); + + process(it, &mut i, ¬much_connection, &list_format, rt, &mut out) + })) + .collect::<Result<_>>() } else { - process_nontree(iter, &mut i, ¬much_connection, &list_format, rt, &mut out) + // use StoreIds to find mails + let iter = rt.ids::<crate::ui::PathProvider>()? + .ok_or_else(|| err_msg("No ids supplied"))? + .into_iter() + .map(Ok) + .into_get_iter(rt.store()) + .map_inner_ok_or_else(|| err_msg("Did not find one entry")) + .and_then_ok(|m| m.is_mail().map(|b| (b, m))) + .filter_ok(|tpl| tpl.0) + .map_ok(|tpl| tpl.1); + + process(iter, &mut i, ¬much_connection, &list_format, rt, &mut out) } } } diff --git a/bin/domain/imag-mail/src/ui.rs b/bin/domain/imag-mail/src/ui.rs index 22562275..3a928d87 100644 --- a/bin/domain/imag-mail/src/ui.rs +++ b/bin/domain/imag-mail/src/ui.rs @@ -24,7 +24,7 @@ use libimagstore::storeid::StoreId; use libimagrt::runtime::IdPathProvider; use libimagstore::storeid::IntoStoreId; -use clap::{Arg, ArgMatches, ArgGroup, App, SubCommand}; +use clap::{Arg, ArgMatches, App, SubCommand}; pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { app @@ -66,6 +66,14 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { .value_name("ID") .help("List mails by Store ID (non-mails will be ignored)")) + .arg(Arg::with_name("query-from-stdin") + .long("stdin") + .short("S") + .takes_value(false) + .required(false) + .multiple(false) + .help("Expect notmuch queries linewise on STDIN, for example from 'notmuch search --output=messages <query>'")) + .arg(Arg::with_name("format") .long("format") .short("f") @@ -74,23 +82,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { .value_name("FORMAT") .help("Format to list entries with (default in config)")) - .arg(Arg::with_name("tree") - .long("tree") - .short("t") - .takes_value(false) - .required(false) - .help("Build a tree and print that. When this argument is passed, the {{indent}} variable is available in the format, otherwise it is set always to zero")) - - .arg(Arg::with_name("find-root") - .long("find-root") - .short("R") - .takes_value(false) - .required(false) - .help("If --tree is passed, this can be used to tell imag to find the root message and starting the tree there instead of the passed mail")) - - .group(ArgGroup::with_name("tree-root") - .arg("find-root") - .requires("tree")) ) .subcommand(SubCommand::with_name("print-id") |