mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-24 20:10:23 +00:00
fix config deserialization issues
This commit is contained in:
parent
efd24251e0
commit
bfb572acbd
8 changed files with 148 additions and 85 deletions
|
@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed config deserialization issue with `email-hooks` and
|
||||
`email-reading-format`.
|
||||
|
||||
## [0.7.1] - 2023-02-14
|
||||
|
||||
### Added
|
||||
|
|
57
Cargo.lock
generated
57
Cargo.lock
generated
|
@ -803,7 +803,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "himalaya-lib"
|
||||
version = "0.6.0"
|
||||
source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#dff1c2354bd480b5997c947c38601b40796f683e"
|
||||
source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#b1a60353ea0577cfeb886433c7a9065c93ad534d"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"chrono",
|
||||
|
@ -1291,6 +1291,15 @@ dependencies = [
|
|||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom8"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
|
||||
dependencies = [
|
||||
"memchr 2.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notmuch"
|
||||
version = "0.8.0"
|
||||
|
@ -1853,18 +1862,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.148"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.148"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1882,6 +1891,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "2.1.2"
|
||||
|
@ -2099,11 +2117,36 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.9"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||
checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nom8",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -45,7 +45,7 @@ serde_json = "1.0"
|
|||
shellexpand = "2.1"
|
||||
termcolor = "1.1"
|
||||
terminal_size = "0.1"
|
||||
toml = "0.5"
|
||||
toml = "0.7.2"
|
||||
unicode-width = "0.1"
|
||||
url = "2.2"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
|
|
51
config.sample.toml
Normal file
51
config.sample.toml
Normal file
|
@ -0,0 +1,51 @@
|
|||
display-name = "Display NAME"
|
||||
signature-delim = "~~"
|
||||
signature = "~/.signature"
|
||||
downloads-dir = "~/downloads"
|
||||
folder-listing-page-size = 12
|
||||
email-listing-page-size = 12
|
||||
email-reading-headers = ["From", "To"]
|
||||
email-reading-verify-cmd = "gpg --verify -q"
|
||||
email-reading-decrypt-cmd = "gpg -dq"
|
||||
email-writing-sign-cmd = "gpg -o - -saq"
|
||||
email-writing-encrypt-cmd = "gpg -o - -eqar <recipient>"
|
||||
|
||||
[example]
|
||||
default = false
|
||||
display-name = "Display NAME (gmail)"
|
||||
email = "display.name@gmail.local"
|
||||
|
||||
backend = "imap"
|
||||
imap-host = "imap.gmail.com"
|
||||
imap-login = "display.name@gmail.local"
|
||||
imap-passwd-cmd = "pass show gmail"
|
||||
imap-port = 993
|
||||
imap-ssl = true
|
||||
imap-starttls = false
|
||||
imap-notify-cmd = """📫 "<sender>" "<subject>""""
|
||||
imap-notify-query = "NOT SEEN"
|
||||
imap-watch-cmds = ["echo \"received server changes!\""]
|
||||
|
||||
sender = "smtp"
|
||||
smtp-host = "smtp.gmail.com"
|
||||
smtp-login = "display.name@gmail.local"
|
||||
smtp-passwd-cmd = "pass show piana/gmail"
|
||||
smtp-port = 465
|
||||
smtp-ssl = true
|
||||
smtp-starttls = false
|
||||
|
||||
sync = true
|
||||
sync-dir = "/tmp/sync/gmail"
|
||||
|
||||
[example.folder-aliases]
|
||||
inbox = "INBOX"
|
||||
drafts = "[Gmail]/Drafts"
|
||||
sent = "[Gmail]/Sent Mail"
|
||||
trash = "[Gmail]/Trash"
|
||||
|
||||
[example.email-hooks]
|
||||
pre-send = "echo $1"
|
||||
|
||||
[example.email-reading-format]
|
||||
type = "fixed"
|
||||
width = 64
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
};
|
||||
|
||||
/// Represents the user config file.
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct DeserializedConfig {
|
||||
#[serde(alias = "name")]
|
||||
|
@ -31,12 +31,8 @@ pub struct DeserializedConfig {
|
|||
|
||||
pub email_listing_page_size: Option<usize>,
|
||||
pub email_reading_headers: Option<Vec<String>>,
|
||||
#[serde(
|
||||
default,
|
||||
with = "EmailTextPlainFormatOptionDef",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub email_reading_format: Option<EmailTextPlainFormat>,
|
||||
#[serde(default, with = "EmailTextPlainFormatDef")]
|
||||
pub email_reading_format: EmailTextPlainFormat,
|
||||
pub email_reading_verify_cmd: Option<String>,
|
||||
pub email_reading_decrypt_cmd: Option<String>,
|
||||
pub email_writing_headers: Option<Vec<String>>,
|
||||
|
@ -44,10 +40,10 @@ pub struct DeserializedConfig {
|
|||
pub email_writing_encrypt_cmd: Option<String>,
|
||||
#[serde(
|
||||
default,
|
||||
with = "EmailHooksOptionDef",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
with = "EmailHooksDef",
|
||||
skip_serializing_if = "EmailHooks::is_empty"
|
||||
)]
|
||||
pub email_hooks: Option<EmailHooks>,
|
||||
pub email_hooks: EmailHooks,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub accounts: HashMap<String, DeserializedAccountConfig>,
|
||||
|
|
|
@ -11,7 +11,7 @@ use himalaya_lib::ImapConfig;
|
|||
#[cfg(feature = "notmuch-backend")]
|
||||
use himalaya_lib::NotmuchConfig;
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "SmtpConfig")]
|
||||
struct SmtpConfigDef {
|
||||
#[serde(rename = "smtp-host")]
|
||||
|
@ -31,7 +31,7 @@ struct SmtpConfigDef {
|
|||
}
|
||||
|
||||
#[cfg(feature = "imap-backend")]
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "ImapConfig")]
|
||||
pub struct ImapConfigDef {
|
||||
#[serde(rename = "imap-host")]
|
||||
|
@ -56,41 +56,39 @@ pub struct ImapConfigDef {
|
|||
pub watch_cmds: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "MaildirConfig")]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "MaildirConfig", rename_all = "kebab-case")]
|
||||
pub struct MaildirConfigDef {
|
||||
#[serde(rename = "maildir-root-dir")]
|
||||
pub root_dir: PathBuf,
|
||||
}
|
||||
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "NotmuchConfig")]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "NotmuchConfig", rename_all = "kebab-case")]
|
||||
pub struct NotmuchConfigDef {
|
||||
#[serde(rename = "notmuch-db-path")]
|
||||
pub db_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "Option<EmailTextPlainFormat>")]
|
||||
pub enum EmailTextPlainFormatOptionDef {
|
||||
#[serde(with = "EmailTextPlainFormatDef")]
|
||||
Some(EmailTextPlainFormat),
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "EmailTextPlainFormat", rename_all = "snake_case")]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(
|
||||
remote = "EmailTextPlainFormat",
|
||||
tag = "type",
|
||||
content = "width",
|
||||
rename_all = "kebab-case"
|
||||
)]
|
||||
pub enum EmailTextPlainFormatDef {
|
||||
#[default]
|
||||
Auto,
|
||||
Flowed,
|
||||
Fixed(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "EmailSender", tag = "sender", rename_all = "snake_case")]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "EmailSender", tag = "sender", rename_all = "kebab-case")]
|
||||
pub enum EmailSenderDef {
|
||||
#[default]
|
||||
None,
|
||||
#[serde(with = "SmtpConfigDef")]
|
||||
Smtp(SmtpConfig),
|
||||
|
@ -98,26 +96,17 @@ pub enum EmailSenderDef {
|
|||
Sendmail(SendmailConfig),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "SendmailConfig")]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "SendmailConfig", rename_all = "kebab-case")]
|
||||
pub struct SendmailConfigDef {
|
||||
#[serde(rename = "sendmail-cmd")]
|
||||
cmd: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "Option<EmailHooks>")]
|
||||
pub enum EmailHooksOptionDef {
|
||||
#[serde(with = "EmailHooksDef")]
|
||||
Some(EmailHooks),
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
/// Represents the email hooks. Useful for doing extra email
|
||||
/// processing before or after sending it.
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "EmailHooks")]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(remote = "EmailHooks", rename_all = "kebab-case")]
|
||||
pub struct EmailHooksDef {
|
||||
/// Represents the hook called just before sending an email.
|
||||
pub pre_send: Option<String>,
|
||||
|
|
|
@ -32,7 +32,6 @@ const SECURITY_PROTOCOLS: &[&str] = &["SSL/TLS", "STARTTLS", "None"];
|
|||
static THEME: Lazy<ColorfulTheme> = Lazy::new(ColorfulTheme::default);
|
||||
|
||||
pub(crate) fn wizard() -> Result<DeserializedConfig> {
|
||||
trace!(">> wizard");
|
||||
println!("Himalaya couldn't find an already existing configuration file.");
|
||||
|
||||
match Confirm::new()
|
||||
|
@ -111,7 +110,7 @@ pub(crate) fn wizard() -> Result<DeserializedConfig> {
|
|||
// Serialize config to file
|
||||
println!("\nWriting the configuration to {path:?}...");
|
||||
fs::create_dir_all(path.parent().unwrap())?;
|
||||
fs::write(path, toml::to_vec(&config)?)?;
|
||||
fs::write(path, toml::to_string(&config)?)?;
|
||||
|
||||
trace!("<< wizard");
|
||||
Ok(config)
|
||||
|
|
|
@ -19,8 +19,8 @@ use std::{collections::HashMap, path::PathBuf};
|
|||
use crate::config::{prelude::*, DeserializedConfig};
|
||||
|
||||
/// Represents all existing kind of account config.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(tag = "backend", rename_all = "snake_case")]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(tag = "backend", rename_all = "kebab-case")]
|
||||
pub enum DeserializedAccountConfig {
|
||||
None(DeserializedBaseAccountConfig),
|
||||
Maildir(DeserializedMaildirAccountConfig),
|
||||
|
@ -70,7 +70,7 @@ impl DeserializedAccountConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct DeserializedBaseAccountConfig {
|
||||
pub email: String,
|
||||
|
@ -85,12 +85,8 @@ pub struct DeserializedBaseAccountConfig {
|
|||
|
||||
pub email_listing_page_size: Option<usize>,
|
||||
pub email_reading_headers: Option<Vec<String>>,
|
||||
#[serde(
|
||||
default,
|
||||
with = "EmailTextPlainFormatOptionDef",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub email_reading_format: Option<EmailTextPlainFormat>,
|
||||
#[serde(default, with = "EmailTextPlainFormatDef")]
|
||||
pub email_reading_format: EmailTextPlainFormat,
|
||||
pub email_reading_verify_cmd: Option<String>,
|
||||
pub email_reading_decrypt_cmd: Option<String>,
|
||||
pub email_writing_headers: Option<Vec<String>>,
|
||||
|
@ -100,10 +96,10 @@ pub struct DeserializedBaseAccountConfig {
|
|||
pub email_sender: EmailSender,
|
||||
#[serde(
|
||||
default,
|
||||
with = "EmailHooksOptionDef",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
with = "EmailHooksDef",
|
||||
skip_serializing_if = "EmailHooks::is_empty"
|
||||
)]
|
||||
pub email_hooks: Option<EmailHooks>,
|
||||
pub email_hooks: EmailHooks,
|
||||
|
||||
#[serde(default)]
|
||||
pub sync: bool,
|
||||
|
@ -159,12 +155,7 @@ impl DeserializedBaseAccountConfig {
|
|||
.as_ref()
|
||||
.map(ToOwned::to_owned)
|
||||
.or_else(|| config.email_reading_headers.as_ref().map(ToOwned::to_owned)),
|
||||
email_reading_format: self
|
||||
.email_reading_format
|
||||
.as_ref()
|
||||
.map(ToOwned::to_owned)
|
||||
.or_else(|| config.email_reading_format.as_ref().map(ToOwned::to_owned))
|
||||
.unwrap_or_default(),
|
||||
email_reading_format: self.email_reading_format.clone(),
|
||||
email_reading_verify_cmd: self
|
||||
.email_reading_verify_cmd
|
||||
.as_ref()
|
||||
|
@ -212,18 +203,7 @@ impl DeserializedBaseAccountConfig {
|
|||
.or_else(|| config.email_writing_headers.as_ref().map(ToOwned::to_owned)),
|
||||
email_sender: self.email_sender.to_owned(),
|
||||
email_hooks: EmailHooks {
|
||||
pre_send: self
|
||||
.email_hooks
|
||||
.as_ref()
|
||||
.map(ToOwned::to_owned)
|
||||
.map(|hook| hook.pre_send)
|
||||
.or_else(|| {
|
||||
config
|
||||
.email_hooks
|
||||
.as_ref()
|
||||
.map(|hook| hook.pre_send.as_ref().map(ToOwned::to_owned))
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
pre_send: self.email_hooks.pre_send.clone(),
|
||||
},
|
||||
sync: self.sync,
|
||||
sync_dir: self.sync_dir.clone(),
|
||||
|
@ -231,7 +211,7 @@ impl DeserializedBaseAccountConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg(feature = "imap-backend")]
|
||||
pub struct DeserializedImapAccountConfig {
|
||||
#[serde(flatten)]
|
||||
|
@ -240,7 +220,7 @@ pub struct DeserializedImapAccountConfig {
|
|||
pub backend: ImapConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
pub struct DeserializedMaildirAccountConfig {
|
||||
#[serde(flatten)]
|
||||
pub base: DeserializedBaseAccountConfig,
|
||||
|
@ -248,7 +228,7 @@ pub struct DeserializedMaildirAccountConfig {
|
|||
pub backend: MaildirConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
pub struct DeserializedNotmuchAccountConfig {
|
||||
#[serde(flatten)]
|
||||
|
|
Loading…
Reference in a new issue