add query arg to envelope list command

This commit is contained in:
Clément DOUIN 2024-02-28 09:09:03 +01:00
parent c28b4c6bb3
commit 1e7adc5e0c
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
8 changed files with 88 additions and 40 deletions

View file

@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Changed
- Changed the `envelope list` options:
- the folder argument became a flag `--folder <name>`
- the query argument has been added at the end of the command to filter and sort results (only filter and IMAP for now)
## [1.0.0-beta.3] - 2024-02-25 ## [1.0.0-beta.3] - 2024-02-25
### Added ### Added

21
Cargo.lock generated
View file

@ -159,6 +159,16 @@ version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
[[package]]
name = "ariadne"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "367fd0ad87307588d087544707bc5fbf4805ded96c7db922b70d368fa1cb5702"
dependencies = [
"unicode-width",
"yansi",
]
[[package]] [[package]]
name = "async-broadcast" name = "async-broadcast"
version = "0.5.1" version = "0.5.1"
@ -1209,13 +1219,13 @@ dependencies = [
[[package]] [[package]]
name = "email-lib" name = "email-lib"
version = "0.22.3" version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://git.sr.ht/~soywod/pimalaya#79af9b0fa5fb30dcb1f8fbd322f7e40b9e05053a"
checksum = "7444aaa4ce80e796febd3def00dd27ec59f4097d65d727cfa5f16dfb07a4fd72"
dependencies = [ dependencies = [
"advisory-lock", "advisory-lock",
"anyhow", "anyhow",
"async-trait", "async-trait",
"chrono", "chrono",
"chumsky",
"convert_case", "convert_case",
"dirs 4.0.0", "dirs 4.0.0",
"email-macros", "email-macros",
@ -1856,6 +1866,7 @@ name = "himalaya"
version = "1.0.0-beta.3" version = "1.0.0-beta.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ariadne",
"async-trait", "async-trait",
"chrono", "chrono",
"clap", "clap",
@ -4956,6 +4967,12 @@ version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]] [[package]]
name = "z-base-32" name = "z-base-32"
version = "0.1.3" version = "0.1.3"

View file

@ -51,6 +51,7 @@ tempfile = "3.3"
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
ariadne = "0.2"
async-trait = "0.1" async-trait = "0.1"
chrono = "0.4.24" chrono = "0.4.24"
clap = { version = "4.4", features = ["derive"] } clap = { version = "4.4", features = ["derive"] }
@ -88,3 +89,6 @@ uuid = { version = "0.8", features = ["v4"] }
[target.'cfg(not(windows))'.dependencies.coredump] [target.'cfg(not(windows))'.dependencies.coredump]
version = "0.1" version = "0.1"
[patch.crates-io]
email-lib = { git = "https://git.sr.ht/~soywod/pimalaya" }

View file

@ -22,7 +22,12 @@ use email::{
backend::{ backend::{
feature::BackendFeature, macros::BackendContext, mapper::SomeBackendContextBuilderMapper, feature::BackendFeature, macros::BackendContext, mapper::SomeBackendContextBuilderMapper,
}, },
envelope::{get::GetEnvelope, list::ListEnvelopes, watch::WatchEnvelopes, Id, SingleId}, envelope::{
get::GetEnvelope,
list::{ListEnvelopes, ListEnvelopesOptions},
watch::WatchEnvelopes,
Id, SingleId,
},
flag::{add::AddFlags, remove::RemoveFlags, set::SetFlags, Flag, Flags}, flag::{add::AddFlags, remove::RemoveFlags, set::SetFlags, Flag, Flags},
folder::{ folder::{
add::AddFolder, delete::DeleteFolder, expunge::ExpungeFolder, list::ListFolders, add::AddFolder, delete::DeleteFolder, expunge::ExpungeFolder, list::ListFolders,
@ -644,12 +649,11 @@ impl Backend {
pub async fn list_envelopes( pub async fn list_envelopes(
&self, &self,
folder: &str, folder: &str,
page_size: usize, opts: ListEnvelopesOptions,
page: usize,
) -> Result<Envelopes> { ) -> Result<Envelopes> {
let backend_kind = self.toml_account_config.list_envelopes_kind(); let backend_kind = self.toml_account_config.list_envelopes_kind();
let id_mapper = self.build_id_mapper(folder, backend_kind)?; let id_mapper = self.build_id_mapper(folder, backend_kind)?;
let envelopes = self.backend.list_envelopes(folder, page_size, page).await?; let envelopes = self.backend.list_envelopes(folder, opts).await?;
let envelopes = Envelopes::from_backend(&self.account_config, &id_mapper, envelopes)?; let envelopes = Envelopes::from_backend(&self.account_config, &id_mapper, envelopes)?;
Ok(envelopes) Ok(envelopes)
} }

29
src/cache/args.rs vendored
View file

@ -1,29 +0,0 @@
//! This module provides arguments related to the cache.
use clap::{Arg, ArgAction, ArgMatches};
const ARG_DISABLE_CACHE: &str = "disable-cache";
/// Represents the disable cache flag argument. This argument allows
/// the user to disable any sort of cache.
pub fn global_args() -> impl IntoIterator<Item = Arg> {
[Arg::new(ARG_DISABLE_CACHE)
.help("Disable any sort of cache")
.long_help(
"Disable any sort of cache.
The action depends on commands it apply on. For example, when listing
envelopes using the IMAP backend, this flag will ensure that envelopes
are fetched from the IMAP server and not from the synchronized local
Maildir.",
)
.long("disable-cache")
.alias("no-cache")
.global(true)
.action(ArgAction::SetTrue)]
}
/// Represents the disable cache flag parser.
pub fn parse_disable_cache_arg(m: &ArgMatches) -> bool {
m.get_flag(ARG_DISABLE_CACHE)
}

1
src/cache/mod.rs vendored
View file

@ -1,5 +1,4 @@
pub mod arg; pub mod arg;
pub mod args;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use dirs::data_dir; use dirs::data_dir;

View file

@ -1,6 +1,7 @@
use anyhow::Result; use anyhow::Result;
use ariadne::{Color, Label, Report, ReportKind, Source};
use clap::Parser; use clap::Parser;
use email::backend::feature::BackendFeatureSource; use email::{backend::feature::BackendFeatureSource, envelope::list::ListEnvelopesOptions};
use log::info; use log::info;
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
@ -9,7 +10,7 @@ use crate::{
account::arg::name::AccountNameFlag, account::arg::name::AccountNameFlag,
backend::Backend, backend::Backend,
config::TomlConfig, config::TomlConfig,
folder::arg::name::FolderNameOptionalArg, folder::arg::name::FolderNameOptionalFlag,
printer::{PrintTableOpts, Printer}, printer::{PrintTableOpts, Printer},
ui::arg::max_width::TableMaxWidthFlag, ui::arg::max_width::TableMaxWidthFlag,
}; };
@ -21,7 +22,7 @@ use crate::{
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct ListEnvelopesCommand { pub struct ListEnvelopesCommand {
#[command(flatten)] #[command(flatten)]
pub folder: FolderNameOptionalArg, pub folder: FolderNameOptionalFlag,
/// The page number. /// The page number.
/// ///
@ -45,6 +46,12 @@ pub struct ListEnvelopesCommand {
#[command(flatten)] #[command(flatten)]
pub account: AccountNameFlag, pub account: AccountNameFlag,
/// The list envelopes filter and sort query.
///
/// TODO
#[arg(allow_hyphen_values = true, trailing_var_arg = true)]
pub query: Option<Vec<String>>,
} }
impl Default for ListEnvelopesCommand { impl Default for ListEnvelopesCommand {
@ -57,6 +64,7 @@ impl Default for ListEnvelopesCommand {
#[cfg(feature = "account-sync")] #[cfg(feature = "account-sync")]
cache: Default::default(), cache: Default::default(),
account: Default::default(), account: Default::default(),
query: Default::default(),
} }
} }
} }
@ -87,7 +95,38 @@ impl ListEnvelopesCommand {
) )
.await?; .await?;
let envelopes = backend.list_envelopes(folder, page_size, page).await?; let filter = match self.query.map(|filter| filter.join(" ").parse()) {
Some(Ok(filter)) => Some(filter),
Some(Err(err)) => {
if let email::envelope::list::Error::ParseFilterError(errs, query) = &err {
errs.into_iter().for_each(|e| {
Report::build(ReportKind::Error, "query", e.span().start)
.with_message(e.to_string())
.with_label(
Label::new(("query", e.span().into_range()))
.with_message(e.reason().to_string())
.with_color(Color::Red),
)
.finish()
.eprint(("query", Source::from(&query)))
.unwrap()
});
};
Err(err)?;
None
}
None => None,
};
let opts = ListEnvelopesOptions {
page,
page_size,
filter,
sort: Default::default(),
};
let envelopes = backend.list_envelopes(folder, opts).await?;
printer.print_table( printer.print_table(
Box::new(envelopes), Box::new(envelopes),

View file

@ -10,6 +10,14 @@ pub struct FolderNameOptionalFlag {
pub name: String, pub name: String,
} }
impl Default for FolderNameOptionalFlag {
fn default() -> Self {
Self {
name: INBOX.to_owned(),
}
}
}
/// The optional folder name argument parser. /// The optional folder name argument parser.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct FolderNameOptionalArg { pub struct FolderNameOptionalArg {