improve notmuch backend logs and error msg

This commit is contained in:
Clément DOUIN 2022-03-01 12:28:20 +01:00
parent 328da34f8d
commit f631f63799
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
2 changed files with 154 additions and 56 deletions

View file

@ -141,10 +141,10 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
let page_begin = page * page_size;
debug!("page begin: {:?}", page_begin);
if page_begin > envelopes.len() {
return Err(anyhow!(format!(
return Err(anyhow!(
"cannot get maildir envelopes at page {:?} (out of bounds)",
page_begin + 1,
)));
));
}
let page_end = envelopes.len().min(page_begin + page_size);
debug!("page end: {:?}", page_end);

View file

@ -1,6 +1,7 @@
use std::{convert::TryInto, fs};
use anyhow::{anyhow, Context, Result};
use log::{debug, info, trace};
use crate::{
backends::{Backend, IdMapper, NotmuchEnvelopes, NotmuchMbox, NotmuchMboxes},
@ -9,6 +10,8 @@ use crate::{
msg::{Envelopes, Msg},
};
/// Represents the Notmuch backend.
#[derive(Debug)]
pub struct NotmuchBackend<'a> {
account_config: &'a AccountConfig,
notmuch_config: &'a NotmuchBackendConfig,
@ -20,24 +23,31 @@ impl<'a> NotmuchBackend<'a> {
account_config: &'a AccountConfig,
notmuch_config: &'a NotmuchBackendConfig,
) -> Result<Self> {
Ok(Self {
info!(">> create new notmuch backend");
let backend = Self {
account_config,
notmuch_config,
db: notmuch::Database::open(
notmuch_config.notmuch_database_dir.clone(),
notmuch::DatabaseMode::ReadWrite,
)
.context(format!(
"cannot open notmuch database at {:?}",
notmuch_config.notmuch_database_dir
))?,
})
.with_context(|| {
format!(
"cannot open notmuch database at {:?}",
notmuch_config.notmuch_database_dir
)
})?,
};
trace!("backend: {:?}", backend);
info!("<< create new notmuch backend");
Ok(backend)
}
fn _search_envelopes(
&mut self,
query: &str,
virt_mbox: &str,
page_size: usize,
page: usize,
) -> Result<Box<dyn Envelopes>> {
@ -45,28 +55,26 @@ impl<'a> NotmuchBackend<'a> {
let query_builder = self
.db
.create_query(query)
.context(format!("cannot create notmuch query from {:?}", query))?;
.with_context(|| format!("cannot create notmuch query from {:?}", query))?;
let mut envelopes: NotmuchEnvelopes = query_builder
.search_messages()
.context(format!(
"cannot find notmuch envelopes from query {:?}",
query
))?
.with_context(|| format!("cannot find notmuch envelopes from query {:?}", query))?
.try_into()
.context(format!(
"cannot parse notmuch envelopes from query {:?}",
query
))?;
.with_context(|| format!("cannot parse notmuch envelopes from query {:?}", query))?;
debug!("envelopes len: {:?}", envelopes.len());
trace!("envelopes: {:?}", envelopes);
// Calculates pagination boundaries.
let page_begin = page * page_size;
debug!("page begin: {:?}", page_begin);
if page_begin > envelopes.len() {
return Err(anyhow!(format!(
"cannot find notmuch envelopes at page {:?} (out of bounds)",
"cannot get notmuch envelopes at page {:?} (out of bounds)",
page_begin + 1,
)));
}
let page_end = envelopes.len().min(page_begin + page_size);
debug!("page end: {:?}", page_end);
// Sorts envelopes by most recent date.
envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap());
@ -74,7 +82,10 @@ impl<'a> NotmuchBackend<'a> {
// Applies pagination boundaries.
envelopes.0 = envelopes[page_begin..page_end].to_owned();
// Appends id <=> hash entries to the id mapper cache file.
// Appends envelopes hash to the id mapper cache file and
// calculates the new short hash length. The short hash length
// represents the minimum hash length possible to avoid
// conflicts.
let short_hash_len = {
let mut mapper = IdMapper::new(&self.notmuch_config.notmuch_database_dir)?;
let entries = envelopes
@ -83,6 +94,7 @@ impl<'a> NotmuchBackend<'a> {
.collect();
mapper.append(entries)?
};
debug!("short hash length: {:?}", short_hash_len);
// Shorten envelopes hash.
envelopes
@ -95,22 +107,35 @@ impl<'a> NotmuchBackend<'a> {
impl<'a> Backend<'a> for NotmuchBackend<'a> {
fn add_mbox(&mut self, _mbox: &str) -> Result<()> {
unimplemented!();
info!(">> add notmuch mailbox");
info!("<< add notmuch mailbox");
Err(anyhow!(
"cannot add notmuch mailbox: feature not implemented"
))
}
fn get_mboxes(&mut self) -> Result<Box<dyn Mboxes>> {
let mut mboxes: Vec<_> = self
info!(">> get notmuch virtual mailboxes");
let mut virt_mboxes: Vec<_> = self
.account_config
.mailboxes
.iter()
.map(|(k, v)| NotmuchMbox::new(k, v))
.collect();
mboxes.sort_by(|a, b| b.name.partial_cmp(&a.name).unwrap());
Ok(Box::new(NotmuchMboxes(mboxes)))
trace!("virtual mailboxes: {:?}", virt_mboxes);
virt_mboxes.sort_by(|a, b| b.name.partial_cmp(&a.name).unwrap());
info!("<< get notmuch virtual mailboxes");
Ok(Box::new(NotmuchMboxes(virt_mboxes)))
}
fn del_mbox(&mut self, _mbox: &str) -> Result<()> {
unimplemented!();
info!(">> delete notmuch mailbox");
info!("<< delete notmuch mailbox");
Err(anyhow!(
"cannot delete notmuch mailbox: feature not implemented"
))
}
fn get_envelopes(
@ -119,13 +144,22 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
page_size: usize,
page: usize,
) -> Result<Box<dyn Envelopes>> {
info!(">> get notmuch envelopes");
debug!("virtual mailbox: {:?}", virt_mbox);
debug!("page size: {:?}", page_size);
debug!("page: {:?}", page);
let query = self
.account_config
.mailboxes
.get(virt_mbox)
.map(|s| s.as_str())
.unwrap_or("all");
self._search_envelopes(query, virt_mbox, page_size, page)
debug!("query: {:?}", query);
let envelopes = self._search_envelopes(query, page_size, page)?;
info!("<< get notmuch envelopes");
Ok(envelopes)
}
fn search_envelopes(
@ -136,69 +170,133 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
page_size: usize,
page: usize,
) -> Result<Box<dyn Envelopes>> {
self._search_envelopes(query, virt_mbox, page_size, page)
info!(">> search notmuch envelopes");
debug!("virtual mailbox: {:?}", virt_mbox);
debug!("query: {:?}", query);
debug!("page size: {:?}", page_size);
debug!("page: {:?}", page);
let query = if query.is_empty() {
self.account_config
.mailboxes
.get(virt_mbox)
.map(|s| s.as_str())
.unwrap_or("all")
} else {
query
};
debug!("final query: {:?}", query);
let envelopes = self._search_envelopes(query, page_size, page)?;
info!("<< search notmuch envelopes");
Ok(envelopes)
}
fn add_msg(&mut self, _mbox: &str, _msg: &[u8], _flags: &str) -> Result<Box<dyn ToString>> {
unimplemented!();
fn add_msg(
&mut self,
_virt_mbox: &str,
_msg: &[u8],
_flags: &str,
) -> Result<Box<dyn ToString>> {
info!(">> add notmuch envelopes");
info!("<< add notmuch envelopes");
Err(anyhow!(
"cannot add notmuch envelopes: feature not implemented"
))
}
fn get_msg(&mut self, _mbox: &str, short_hash: &str) -> Result<Msg> {
let id = IdMapper::new(&self.notmuch_config.notmuch_database_dir)?
fn get_msg(&mut self, _virt_mbox: &str, short_hash: &str) -> Result<Msg> {
info!(">> add notmuch envelopes");
debug!("short hash: {:?}", short_hash);
let dir = &self.notmuch_config.notmuch_database_dir;
let id = IdMapper::new(dir)
.with_context(|| format!("cannot create id mapper instance for {:?}", dir))?
.find(short_hash)
.context(format!(
"cannot get notmuch message from short hash {:?}",
short_hash
))?;
let msg_filepath = self
.with_context(|| {
format!(
"cannot find notmuch message from short hash {:?}",
short_hash
)
})?;
debug!("id: {:?}", id);
let msg_file_path = self
.db
.find_message(&id)
.context(format!("cannot find notmuch message {:?}", id))?
.with_context(|| format!("cannot find notmuch message {:?}", id))?
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
.filename()
.to_owned();
let raw_msg = fs::read(&msg_filepath)
.context(format!("cannot read message from file {:?}", msg_filepath))?;
let msg = Msg::from_parsed_mail(mailparse::parse_mail(&raw_msg)?, &self.account_config)?;
debug!("message file path: {:?}", msg_file_path);
let raw_msg = fs::read(&msg_file_path).with_context(|| {
format!("cannot read notmuch message from file {:?}", msg_file_path)
})?;
let msg = mailparse::parse_mail(&raw_msg)
.with_context(|| format!("cannot parse raw notmuch message {:?}", id))?;
let msg = Msg::from_parsed_mail(msg, &self.account_config)
.with_context(|| format!("cannot parse notmuch message {:?}", id))?;
trace!("message: {:?}", msg);
info!("<< get notmuch message");
Ok(msg)
}
fn copy_msg(&mut self, _mbox_src: &str, _mbox_dst: &str, _id: &str) -> Result<()> {
unimplemented!();
info!(">> copy notmuch message");
info!("<< copy notmuch message");
Err(anyhow!(
"cannot copy notmuch message: feature not implemented"
))
}
fn move_msg(&mut self, _mbox_src: &str, _mbox_dst: &str, _id: &str) -> Result<()> {
unimplemented!();
fn move_msg(&mut self, _src: &str, _dst: &str, _id: &str) -> Result<()> {
info!(">> move notmuch message");
info!("<< move notmuch message");
Err(anyhow!(
"cannot move notmuch message: feature not implemented"
))
}
fn del_msg(&mut self, _mbox: &str, short_hash: &str) -> Result<()> {
let id = IdMapper::new(&self.notmuch_config.notmuch_database_dir)?
fn del_msg(&mut self, _virt_mbox: &str, short_hash: &str) -> Result<()> {
info!(">> delete notmuch message");
debug!("short hash: {:?}", short_hash);
let dir = &self.notmuch_config.notmuch_database_dir;
let id = IdMapper::new(dir)
.with_context(|| format!("cannot create id mapper instance for {:?}", dir))?
.find(short_hash)
.context(format!(
"cannot get notmuch message from short hash {:?}",
short_hash
))?;
let msg_filepath = self
.with_context(|| {
format!(
"cannot find notmuch message from short hash {:?}",
short_hash
)
})?;
debug!("id: {:?}", id);
let msg_file_path = self
.db
.find_message(&id)
.context(format!("cannot find notmuch message {:?}", id))?
.with_context(|| format!("cannot find notmuch message {:?}", id))?
.ok_or_else(|| anyhow!("cannot find notmuch message {:?}", id))?
.filename()
.to_owned();
debug!("message file path: {:?}", msg_file_path);
self.db
.remove_message(msg_filepath)
.context(format!("cannot delete notmuch message {:?}", id))
.remove_message(msg_file_path)
.with_context(|| format!("cannot delete notmuch message {:?}", id))?;
info!("<< delete notmuch message");
Ok(())
}
fn add_flags(&mut self, _mbox: &str, _id: &str, _flags_str: &str) -> Result<()> {
fn add_flags(&mut self, _virt_mbox: &str, _id: &str, _flags: &str) -> Result<()> {
unimplemented!();
}
fn set_flags(&mut self, _mbox: &str, _id: &str, _flags_str: &str) -> Result<()> {
fn set_flags(&mut self, _virt_mbox: &str, _id: &str, _flags: &str) -> Result<()> {
unimplemented!();
}
fn del_flags(&mut self, _mbox: &str, _id: &str, _flags_str: &str) -> Result<()> {
fn del_flags(&mut self, _virt_mbox: &str, _id: &str, _flags: &str) -> Result<()> {
unimplemented!();
}
}