core: split commands in their own module
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>add-rfc9500-test-keys
parent
250eb0a2ab
commit
6f13cd1e31
|
@ -102,12 +102,7 @@ pub enum Command {
|
|||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
},
|
||||
/// Mail that has not been handled properly end up in the error queue.
|
||||
ErrorQueue {
|
||||
#[command(subcommand)]
|
||||
cmd: QueueCommand,
|
||||
},
|
||||
/// Mail that has not been handled properly end up in the error queue.
|
||||
/// Processed mail is stored in queues.
|
||||
Queue {
|
||||
#[arg(long, value_parser = QueueValueParser)]
|
||||
queue: mailpot::queue::Queue,
|
||||
|
@ -275,9 +270,6 @@ pub enum QueueCommand {
|
|||
/// index of entry.
|
||||
#[arg(long)]
|
||||
index: Vec<i64>,
|
||||
/// Do not print in stdout.
|
||||
#[arg(long)]
|
||||
quiet: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,8 @@ extern crate ureq;
|
|||
pub use std::path::PathBuf;
|
||||
|
||||
mod args;
|
||||
pub mod commands;
|
||||
pub mod import;
|
||||
pub mod lints;
|
||||
pub use args::*;
|
||||
pub use clap::{Args, CommandFactory, Parser, Subcommand};
|
||||
|
|
|
@ -17,7 +17,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
use mailpot::{
|
||||
chrono,
|
||||
melib::{self, Envelope},
|
||||
models::{Account, DbVal, ListSubscription, MailingList},
|
||||
rusqlite, Connection, Result,
|
||||
};
|
||||
|
||||
pub fn datetime_header_value_lint(db: &mut Connection, dry_run: bool) -> Result<()> {
|
||||
let mut col = vec![];
|
||||
|
|
1038
cli/src/main.rs
1038
cli/src/main.rs
File diff suppressed because it is too large
Load Diff
|
@ -104,6 +104,31 @@ For more information, try '--help'."#,
|
|||
|
||||
let config_str = config.to_toml();
|
||||
|
||||
fn config_not_exists(conf: &Path) {
|
||||
let mut cmd = Command::cargo_bin("mpot").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg(conf)
|
||||
.arg("list-lists")
|
||||
.output()
|
||||
.unwrap()
|
||||
.assert();
|
||||
output.code(255).stderr(predicates::str::is_empty()).stdout(
|
||||
predicate::eq(
|
||||
format!(
|
||||
"[1] Could not read configuration file from path: {} Caused by:\n[2] Error \
|
||||
returned from internal I/O operation: No such file or directory (os error 2)",
|
||||
conf.display()
|
||||
)
|
||||
.as_str(),
|
||||
)
|
||||
.trim()
|
||||
.normalize(),
|
||||
);
|
||||
}
|
||||
|
||||
config_not_exists(&conf_path);
|
||||
|
||||
std::fs::write(&conf_path, config_str.as_bytes()).unwrap();
|
||||
|
||||
fn list_lists(conf: &Path, eq: &str) {
|
||||
|
@ -178,4 +203,65 @@ For more information, try '--help'."#,
|
|||
\"twobar-chat@example.com\", topics: [], description: None, archive_url: None }, \
|
||||
2)\n\tList owners: None\n\tPost policy: None\n\tSubscription policy: None",
|
||||
);
|
||||
|
||||
fn add_list_owner(conf: &Path) {
|
||||
let mut cmd = Command::cargo_bin("mpot").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg(conf)
|
||||
.arg("list")
|
||||
.arg("twobar-chat")
|
||||
.arg("add-list-owner")
|
||||
.arg("--address")
|
||||
.arg("list-owner@example.com")
|
||||
.output()
|
||||
.unwrap()
|
||||
.assert();
|
||||
output.code(0).stderr(predicates::str::is_empty()).stdout(
|
||||
predicate::eq("Added new list owner [#1 2] list-owner@example.com")
|
||||
.trim()
|
||||
.normalize(),
|
||||
);
|
||||
}
|
||||
add_list_owner(&conf_path);
|
||||
list_lists(
|
||||
&conf_path,
|
||||
"- foo-chat DbVal(MailingList { pk: 1, name: \"foobar chat\", id: \"foo-chat\", address: \
|
||||
\"foo-chat@example.com\", topics: [], description: None, archive_url: None }, 1)\n\tList \
|
||||
owners: None\n\tPost policy: None\n\tSubscription policy: None\n\n- twobar-chat \
|
||||
DbVal(MailingList { pk: 2, name: \"twobar\", id: \"twobar-chat\", address: \
|
||||
\"twobar-chat@example.com\", topics: [], description: None, archive_url: None }, \
|
||||
2)\n\tList owners:\n\t- [#1 2] list-owner@example.com\n\tPost policy: \
|
||||
None\n\tSubscription policy: None",
|
||||
);
|
||||
|
||||
fn remove_list_owner(conf: &Path) {
|
||||
let mut cmd = Command::cargo_bin("mpot").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg(conf)
|
||||
.arg("list")
|
||||
.arg("twobar-chat")
|
||||
.arg("remove-list-owner")
|
||||
.arg("--pk")
|
||||
.arg("1")
|
||||
.output()
|
||||
.unwrap()
|
||||
.assert();
|
||||
output.code(0).stderr(predicates::str::is_empty()).stdout(
|
||||
predicate::eq("Removed list owner with pk = 1")
|
||||
.trim()
|
||||
.normalize(),
|
||||
);
|
||||
}
|
||||
remove_list_owner(&conf_path);
|
||||
list_lists(
|
||||
&conf_path,
|
||||
"- foo-chat DbVal(MailingList { pk: 1, name: \"foobar chat\", id: \"foo-chat\", address: \
|
||||
\"foo-chat@example.com\", topics: [], description: None, archive_url: None }, 1)\n\tList \
|
||||
owners: None\n\tPost policy: None\n\tSubscription policy: None\n\n- twobar-chat \
|
||||
DbVal(MailingList { pk: 2, name: \"twobar\", id: \"twobar-chat\", address: \
|
||||
\"twobar-chat@example.com\", topics: [], description: None, archive_url: None }, \
|
||||
2)\n\tList owners: None\n\tPost policy: None\n\tSubscription policy: None",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -78,10 +78,12 @@ impl Configuration {
|
|||
let mut s = String::new();
|
||||
let mut file = std::fs::File::open(path)?;
|
||||
file.read_to_string(&mut s)?;
|
||||
let config: Self = toml::from_str(&s).context(format!(
|
||||
"Could not parse configuration file `{}` succesfully: ",
|
||||
path.display()
|
||||
))?;
|
||||
let config: Self = toml::from_str(&s)
|
||||
.map_err(anyhow::Error::from)
|
||||
.context(format!(
|
||||
"Could not parse configuration file `{}` successfully: ",
|
||||
path.display()
|
||||
))?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
@ -127,3 +129,29 @@ impl Configuration {
|
|||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_config_parse_error() {
|
||||
let tmp_dir = TempDir::new().unwrap();
|
||||
let conf_path = tmp_dir.path().join("conf.toml");
|
||||
std::fs::write(&conf_path, b"afjsad skas as a as\n\n\n\n\t\x11\n").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
Configuration::from_file(&conf_path)
|
||||
.unwrap_err()
|
||||
.display_chain()
|
||||
.to_string(),
|
||||
format!(
|
||||
"[1] Could not parse configuration file `{}` successfully: Caused by:\n[2] \
|
||||
Error: expected an equals, found an identifier at line 1 column 8\n",
|
||||
conf_path.display()
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -617,7 +617,7 @@ impl Connection {
|
|||
if matches!(err, rusqlite::Error::QueryReturnedNoRows) {
|
||||
Error::from(err).chain_err(|| NotFound("list or list owner not found!"))
|
||||
} else {
|
||||
err.into()
|
||||
Error::from(err)
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
|
|
|
@ -23,8 +23,6 @@ use std::sync::Arc;
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
pub use crate::anyhow::Context;
|
||||
|
||||
/// Mailpot library error.
|
||||
#[derive(Error, Debug)]
|
||||
pub struct Error {
|
||||
|
@ -53,39 +51,36 @@ pub enum ErrorKind {
|
|||
|
||||
/// Error returned from an external user initiated operation such as
|
||||
/// deserialization or I/O.
|
||||
#[error(
|
||||
"Error returned from an external user initiated operation such as deserialization or I/O. \
|
||||
{0}"
|
||||
)]
|
||||
#[error("Error: {0}")]
|
||||
External(#[from] anyhow::Error),
|
||||
/// Generic
|
||||
#[error("{0}")]
|
||||
Generic(anyhow::Error),
|
||||
/// Error returned from sqlite3.
|
||||
#[error("Error returned from sqlite3 {0}.")]
|
||||
#[error("Error returned from sqlite3: {0}.")]
|
||||
Sql(
|
||||
#[from]
|
||||
#[source]
|
||||
rusqlite::Error,
|
||||
),
|
||||
/// Error returned from sqlite3.
|
||||
#[error("Error returned from sqlite3. {0}")]
|
||||
#[error("Error returned from sqlite3: {0}")]
|
||||
SqlLib(
|
||||
#[from]
|
||||
#[source]
|
||||
rusqlite::ffi::Error,
|
||||
),
|
||||
/// Error returned from internal I/O operations.
|
||||
#[error("Error returned from internal I/O operations. {0}")]
|
||||
#[error("Error returned from internal I/O operation: {0}")]
|
||||
Io(#[from] ::std::io::Error),
|
||||
/// Error returned from e-mail protocol operations from `melib` crate.
|
||||
#[error("Error returned from e-mail protocol operations from `melib` crate. {0}")]
|
||||
#[error("Error returned from e-mail protocol operations from `melib` crate: {0}")]
|
||||
Melib(#[from] melib::error::Error),
|
||||
/// Error from deserializing JSON values.
|
||||
#[error("Error from deserializing JSON values. {0}")]
|
||||
#[error("Error from deserializing JSON values: {0}")]
|
||||
SerdeJson(#[from] serde_json::Error),
|
||||
/// Error returned from minijinja template engine.
|
||||
#[error("Error returned from minijinja template engine. {0}")]
|
||||
#[error("Error returned from minijinja template engine: {0}")]
|
||||
Template(#[from] minijinja::Error),
|
||||
}
|
||||
|
||||
|
@ -188,7 +183,7 @@ struct ErrorChainDisplay<'e> {
|
|||
impl std::fmt::Display for ErrorChainDisplay<'_> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
if let Some(ref source) = self.current.source {
|
||||
writeln!(fmt, "[{}] {}, caused by:", self.counter, self.current.kind)?;
|
||||
writeln!(fmt, "[{}] {} Caused by:", self.counter, self.current.kind)?;
|
||||
Self {
|
||||
current: source,
|
||||
counter: self.counter + 1,
|
||||
|
@ -200,3 +195,38 @@ impl std::fmt::Display for ErrorChainDisplay<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// adfsa
|
||||
pub trait Context<T> {
|
||||
/// Wrap the error value with additional context.
|
||||
fn context<C>(self, context: C) -> Result<T>
|
||||
where
|
||||
C: Into<Error>;
|
||||
|
||||
/// Wrap the error value with additional context that is evaluated lazily
|
||||
/// only once an error does occur.
|
||||
fn with_context<C, F>(self, f: F) -> Result<T>
|
||||
where
|
||||
C: Into<Error>,
|
||||
F: FnOnce() -> C;
|
||||
}
|
||||
|
||||
impl<T, E> Context<T> for std::result::Result<T, E>
|
||||
where
|
||||
Error: From<E>,
|
||||
{
|
||||
fn context<C>(self, context: C) -> Result<T>
|
||||
where
|
||||
C: Into<Error>,
|
||||
{
|
||||
self.map_err(|err| Error::from(err).chain_err(|| context.into()))
|
||||
}
|
||||
|
||||
fn with_context<C, F>(self, f: F) -> Result<T>
|
||||
where
|
||||
C: Into<Error>,
|
||||
F: FnOnce() -> C,
|
||||
{
|
||||
self.map_err(|err| Error::from(err).chain_err(|| f().into()))
|
||||
}
|
||||
}
|
||||
|
|
62
docs/mpot.1
62
docs/mpot.1
|
@ -705,61 +705,6 @@ Show e\-mail processing result without actually consuming it.
|
|||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\fB
|
||||
.SS mpot error-queue
|
||||
.\fR
|
||||
.br
|
||||
|
||||
.br
|
||||
|
||||
Mail that has not been handled properly end up in the error queue.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\fB
|
||||
.SS mpot error-queue list
|
||||
.\fR
|
||||
.br
|
||||
|
||||
.br
|
||||
|
||||
List.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\fB
|
||||
.SS mpot error-queue print
|
||||
.\fR
|
||||
.br
|
||||
|
||||
.br
|
||||
|
||||
mpot error\-queue print [\-\-index \fIINDEX\fR]
|
||||
.br
|
||||
|
||||
Print entry in RFC5322 or JSON format.
|
||||
.TP
|
||||
\-\-index \fIINDEX\fR
|
||||
index of entry.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\fB
|
||||
.SS mpot error-queue delete
|
||||
.\fR
|
||||
.br
|
||||
|
||||
.br
|
||||
|
||||
mpot error\-queue delete [\-\-index \fIINDEX\fR] [\-\-quiet \fIQUIET\fR]
|
||||
.br
|
||||
|
||||
Delete entry and print it in stdout.
|
||||
.TP
|
||||
\-\-index \fIINDEX\fR
|
||||
index of entry.
|
||||
.TP
|
||||
\-\-quiet
|
||||
Do not print in stdout.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\fB
|
||||
.SS mpot queue
|
||||
.\fR
|
||||
.br
|
||||
|
@ -769,7 +714,7 @@ Do not print in stdout.
|
|||
mpot queue \-\-queue \fIQUEUE\fR
|
||||
.br
|
||||
|
||||
Mail that has not been handled properly end up in the error queue.
|
||||
Processed mail is stored in queues.
|
||||
.TP
|
||||
\-\-queue \fIQUEUE\fR
|
||||
|
||||
|
@ -810,16 +755,13 @@ index of entry.
|
|||
|
||||
.br
|
||||
|
||||
mpot queue delete [\-\-index \fIINDEX\fR] [\-\-quiet \fIQUIET\fR]
|
||||
mpot queue delete [\-\-index \fIINDEX\fR]
|
||||
.br
|
||||
|
||||
Delete entry and print it in stdout.
|
||||
.TP
|
||||
\-\-index \fIINDEX\fR
|
||||
index of entry.
|
||||
.TP
|
||||
\-\-quiet
|
||||
Do not print in stdout.
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\fB
|
||||
|
|
Loading…
Reference in New Issue