From 7fbe39b8fb981f05eae30ef3261c458225f6c1e0 Mon Sep 17 00:00:00 2001 From: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com> Date: Thu, 16 Feb 2023 19:44:26 +0530 Subject: [PATCH 01/19] Add Scoop install method --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index ebc9690..a494021 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,9 @@ $ yay -S himalaya-git # Homebrew $ brew install himalaya +# Scoop +$ scoop install himalaya + # Cargo $ cargo install himalaya From beba35d57e31ab345649d54f3a527a4008753559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Thu, 16 Feb 2023 16:15:01 +0100 Subject: [PATCH 02/19] use develop branch of himalaya-lib --- Cargo.lock | 13 +++++++++++-- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ded212d..a560093 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,8 +797,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6aa84cdd1cec7bd25e319f0decd7d6ec5d765fb983da7a0dea10d797f7e73a8" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#f3708e90fe1b2c4003d4e1b08c906eef820817cb" dependencies = [ "ammonia", "chrono", @@ -809,6 +808,7 @@ dependencies = [ "imap-proto", "lettre", "log", + "mail-parser", "maildir", "mailparse", "md5", @@ -1116,6 +1116,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mail-parser" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2e03aa1d18528b45d0e79e46790f38cfeece6cce3af17a85912677272f36cd" +dependencies = [ + "encoding_rs", +] + [[package]] name = "maildir" version = "0.6.3" diff --git a/Cargo.toml b/Cargo.toml index bd282e4..6a8f0da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ dialoguer = "0.10.2" email_address = "0.2.4" env_logger = "0.8" erased-serde = "0.3" -himalaya-lib = "0.6.0" +himalaya-lib = { git = "https://git.sr.ht/~soywod/himalaya-lib", branch = "develop" } indicatif = "0.17" log = "0.4" once_cell = "1.16.0" From efd24251e02644c55feb5720c452ba87a60f0fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Sat, 18 Feb 2023 10:08:26 +0100 Subject: [PATCH 03/19] bump himalaya-lib version --- Cargo.lock | 79 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a560093..c834e99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "bitflags" version = "1.3.2" @@ -136,7 +142,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18e9079d1a12a2cc2bffb5db039c43661836ead4082120d5844f02555aca2d46" dependencies = [ - "base64", + "base64 0.13.1", "encoding_rs", ] @@ -500,11 +506,11 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "email-encoding" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34dd14c63662e0206599796cd5e1ad0268ab2b9d19b868d6050d688eba2bbf98" +checksum = "dbfb21b9878cf7a348dcb8559109aabc0ec40d69924bd706fa5149846c4fef75" dependencies = [ - "base64", + "base64 0.21.0", "memchr 2.5.0", ] @@ -797,7 +803,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#f3708e90fe1b2c4003d4e1b08c906eef820817cb" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#dff1c2354bd480b5997c947c38601b40796f683e" dependencies = [ "ammonia", "chrono", @@ -906,17 +912,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.3.0" @@ -933,7 +928,7 @@ version = "3.0.0-alpha.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c2ff52273d9cd791687b4510d8a0047277e985a348e411c94fe84e193e7a76" dependencies = [ - "base64", + "base64 0.13.1", "bufstream", "chrono", "imap-proto", @@ -1029,18 +1024,18 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lettre" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eabca5e0b4d0e98e7f2243fb5b7520b6af2b65d8f87bcc86f2c75185a6ff243" +checksum = "dd84a055407850bcf4791baa77cb4818d37cbb79ad4e60b9b659727b920d2c65" dependencies = [ - "base64", + "base64 0.21.0", "email-encoding", "email_address", "fastrand", "futures-util", "hostname", "httpdate", - "idna 0.2.3", + "idna", "mime", "native-tls", "nom 7.1.1", @@ -1048,6 +1043,7 @@ dependencies = [ "quoted_printable", "serde", "socket2", + "tokio", ] [[package]] @@ -1173,12 +1169,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "md5" version = "0.7.0" @@ -1227,8 +1217,7 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "mime-msg-builder" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3981dce6db3e7f9faa1124409a6b94436902ecb2670f374d361789d61eb34ac" +source = "git+https://git.sr.ht/~soywod/mime-msg-builder?branch=develop#1f61083ba7811bf261647056e63441d2f997113c" dependencies = [ "ammonia", "chumsky 0.9.0", @@ -1247,6 +1236,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.42.0", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -1757,7 +1758,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11347d014ae34e1d367aaf9191c37bf071b161e2e1c09c8559c7717e87030e11" dependencies = [ - "base64", + "base64 0.13.1", "charset", "chumsky 0.8.0", "memchr 2.5.0", @@ -2082,6 +2083,20 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +[[package]] +name = "tokio" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +dependencies = [ + "autocfg", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.42.0", +] + [[package]] name = "toml" version = "0.5.9" @@ -2138,7 +2153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna", "percent-encoding", ] @@ -2160,7 +2175,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e326365261fc2761f0809dfb6032810534a0427bbd8f0edf546f6afeef89f5d" dependencies = [ - "base64", + "base64 0.13.1", "encoding_rs", "regex", ] From bfb572acbd1504851157875d73985983221485be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Sat, 18 Feb 2023 21:12:47 +0100 Subject: [PATCH 04/19] fix config deserialization issues --- CHANGELOG.md | 5 ++++ Cargo.lock | 57 +++++++++++++++++++++++++++++++----- Cargo.toml | 2 +- config.sample.toml | 51 ++++++++++++++++++++++++++++++++ src/config/config.rs | 16 ++++------ src/config/prelude.rs | 53 +++++++++++++-------------------- src/config/wizard/mod.rs | 3 +- src/domain/account/config.rs | 46 ++++++++--------------------- 8 files changed, 148 insertions(+), 85 deletions(-) create mode 100644 config.sample.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index 891d90d..2149b72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/Cargo.lock b/Cargo.lock index c834e99..9a18f28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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]] diff --git a/Cargo.toml b/Cargo.toml index 6a8f0da..2add42a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } diff --git a/config.sample.toml b/config.sample.toml new file mode 100644 index 0000000..a18f3a8 --- /dev/null +++ b/config.sample.toml @@ -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 " + +[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 = """šŸ“« "" """"" +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 diff --git a/src/config/config.rs b/src/config/config.rs index dbb96d3..1d7744a 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -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, pub email_reading_headers: Option>, - #[serde( - default, - with = "EmailTextPlainFormatOptionDef", - skip_serializing_if = "Option::is_none" - )] - pub email_reading_format: Option, + #[serde(default, with = "EmailTextPlainFormatDef")] + pub email_reading_format: EmailTextPlainFormat, pub email_reading_verify_cmd: Option, pub email_reading_decrypt_cmd: Option, pub email_writing_headers: Option>, @@ -44,10 +40,10 @@ pub struct DeserializedConfig { pub email_writing_encrypt_cmd: Option, #[serde( default, - with = "EmailHooksOptionDef", - skip_serializing_if = "Option::is_none" + with = "EmailHooksDef", + skip_serializing_if = "EmailHooks::is_empty" )] - pub email_hooks: Option, + pub email_hooks: EmailHooks, #[serde(flatten)] pub accounts: HashMap, diff --git a/src/config/prelude.rs b/src/config/prelude.rs index 9f30f97..8d4f830 100644 --- a/src/config/prelude.rs +++ b/src/config/prelude.rs @@ -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>, } -#[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")] -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")] -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, diff --git a/src/config/wizard/mod.rs b/src/config/wizard/mod.rs index 2282af8..cc58608 100644 --- a/src/config/wizard/mod.rs +++ b/src/config/wizard/mod.rs @@ -32,7 +32,6 @@ const SECURITY_PROTOCOLS: &[&str] = &["SSL/TLS", "STARTTLS", "None"]; static THEME: Lazy = Lazy::new(ColorfulTheme::default); pub(crate) fn wizard() -> Result { - trace!(">> wizard"); println!("Himalaya couldn't find an already existing configuration file."); match Confirm::new() @@ -111,7 +110,7 @@ pub(crate) fn wizard() -> Result { // 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) diff --git a/src/domain/account/config.rs b/src/domain/account/config.rs index fa76224..046d7e8 100644 --- a/src/domain/account/config.rs +++ b/src/domain/account/config.rs @@ -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, pub email_reading_headers: Option>, - #[serde( - default, - with = "EmailTextPlainFormatOptionDef", - skip_serializing_if = "Option::is_none" - )] - pub email_reading_format: Option, + #[serde(default, with = "EmailTextPlainFormatDef")] + pub email_reading_format: EmailTextPlainFormat, pub email_reading_verify_cmd: Option, pub email_reading_decrypt_cmd: Option, pub email_writing_headers: Option>, @@ -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, + 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)] From 4b3280cbbb954c07c5354955f507d5039de7d90f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Mon, 20 Feb 2023 10:03:55 +0100 Subject: [PATCH 05/19] bump himalaya-lib b1a1834d --- Cargo.lock | 2 +- Cargo.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 9a18f28..56753f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -803,7 +803,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#b1a60353ea0577cfeb886433c7a9065c93ad534d" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#b1a1834dc920965c9449a708ee1b9fa24f8a5135" dependencies = [ "ammonia", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 2add42a..3e5690f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ email_address = "0.2.4" env_logger = "0.8" erased-serde = "0.3" himalaya-lib = { git = "https://git.sr.ht/~soywod/himalaya-lib", branch = "develop" } +# himalaya-lib = { path = "/home/soywod/sourcehut/himalaya-lib" } indicatif = "0.17" log = "0.4" once_cell = "1.16.0" From 0ab652b4b6d399cb0bd0b1629ebb029984c921b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Mon, 20 Feb 2023 11:57:41 +0100 Subject: [PATCH 06/19] bump himalaya-lib 8c53868 --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 56753f1..8828de9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -803,7 +803,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#b1a1834dc920965c9449a708ee1b9fa24f8a5135" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#8c538689c9d3098f8e69493791ccbbe52eb9af58" dependencies = [ "ammonia", "chrono", From 3631ca714b6d3562e1df1b330f5b8a255b270bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Mon, 20 Feb 2023 17:41:26 +0100 Subject: [PATCH 07/19] fix flags case sensitivity --- CHANGELOG.md | 1 + Cargo.lock | 4 +-- Cargo.toml | 1 + src/domain/email/handlers.rs | 15 +++++--- src/domain/envelope/envelope.rs | 61 +++++++++++++++++++++++++++++--- src/domain/envelope/envelopes.rs | 23 +++++++++++- src/domain/flag/args.rs | 6 +++- src/domain/flag/flag.rs | 25 +++++++++++++ src/domain/flag/flags.rs | 21 +++++++++++ src/domain/flag/mod.rs | 6 ++++ src/domain/folder/folder.rs | 19 +++++++++- src/domain/folder/folders.rs | 22 +++++++++++- src/domain/folder/handlers.rs | 7 ++-- 13 files changed, 194 insertions(+), 17 deletions(-) create mode 100644 src/domain/flag/flag.rs create mode 100644 src/domain/flag/flags.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 2149b72..8afdb04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed config deserialization issue with `email-hooks` and `email-reading-format`. +- Fixed flags case sensitivity. ## [0.7.1] - 2023-02-14 diff --git a/Cargo.lock b/Cargo.lock index 8828de9..b152a64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -775,6 +775,7 @@ version = "0.7.1" dependencies = [ "anyhow", "atty", + "chrono", "clap", "clap_complete", "clap_mangen", @@ -803,7 +804,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#8c538689c9d3098f8e69493791ccbbe52eb9af58" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#26d3b9e74c978f6dc94689bff809d48fe5ba4c85" dependencies = [ "ammonia", "chrono", @@ -827,7 +828,6 @@ dependencies = [ "regex", "rfc2047-decoder", "rusqlite", - "serde", "shellexpand", "thiserror", "tree_magic", diff --git a/Cargo.toml b/Cargo.toml index 3e5690f..7d47001 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ tempfile = "3.3" [dependencies] anyhow = "1.0" atty = "0.2" +chrono = "0.4.23" clap = "4.0" clap_complete = "4.0" clap_mangen = "0.2" diff --git a/src/domain/email/handlers.rs b/src/domain/email/handlers.rs index 3261a02..c44a35e 100644 --- a/src/domain/email/handlers.rs +++ b/src/domain/email/handlers.rs @@ -14,6 +14,7 @@ use uuid::Uuid; use crate::{ printer::{PrintTableOpts, Printer}, ui::editor, + Envelopes, }; pub fn attachments( @@ -132,10 +133,10 @@ pub fn list( let folder = config.folder_alias(folder)?; let page_size = page_size.unwrap_or(config.email_listing_page_size()); debug!("page size: {}", page_size); - let msgs = backend.list_envelopes(&folder, page_size, page)?; - trace!("envelopes: {:?}", msgs); + let envelopes: Envelopes = backend.list_envelopes(&folder, page_size, page)?.into(); + trace!("envelopes: {:?}", envelopes); printer.print_table( - Box::new(msgs), + Box::new(envelopes), PrintTableOpts { format: &config.email_reading_format, max_width, @@ -291,7 +292,9 @@ pub fn search( ) -> Result<()> { let folder = config.folder_alias(folder)?; let page_size = page_size.unwrap_or(config.email_listing_page_size()); - let envelopes = backend.search_envelopes(&folder, &query, "", page_size, page)?; + let envelopes: Envelopes = backend + .search_envelopes(&folder, &query, "", page_size, page)? + .into(); let opts = PrintTableOpts { format: &config.email_reading_format, max_width, @@ -313,7 +316,9 @@ pub fn sort( ) -> Result<()> { let folder = config.folder_alias(folder)?; let page_size = page_size.unwrap_or(config.email_listing_page_size()); - let envelopes = backend.search_envelopes(&folder, &query, &sort, page_size, page)?; + let envelopes: Envelopes = backend + .search_envelopes(&folder, &query, &sort, page_size, page)? + .into(); let opts = PrintTableOpts { format: &config.email_reading_format, max_width, diff --git a/src/domain/envelope/envelope.rs b/src/domain/envelope/envelope.rs index a62254f..5c24133 100644 --- a/src/domain/envelope/envelope.rs +++ b/src/domain/envelope/envelope.rs @@ -1,6 +1,45 @@ -use himalaya_lib::{Envelope, Flag}; +use chrono::{DateTime, Local}; +use serde::{Serialize, Serializer}; -use crate::ui::{Cell, Row, Table}; +use crate::{ + ui::{Cell, Row, Table}, + Flag, Flags, +}; + +fn date(date: &DateTime, s: S) -> Result { + s.serialize_str(&date.to_rfc3339()) +} + +#[derive(Clone, Debug, Default, Serialize)] +pub struct Mailbox { + pub name: Option, + pub addr: String, +} + +#[derive(Clone, Debug, Default, Serialize)] +pub struct Envelope { + pub id: String, + pub flags: Flags, + pub subject: String, + pub from: Mailbox, + #[serde(serialize_with = "date")] + pub date: DateTime, +} + +impl From<&himalaya_lib::Envelope> for Envelope { + fn from(envelope: &himalaya_lib::Envelope) -> Self { + Envelope { + id: envelope.id.clone(), + flags: envelope.flags.clone().into(), + subject: envelope.subject.clone(), + from: Mailbox { + name: envelope.from.name.clone(), + addr: envelope.from.addr.clone(), + }, + date: envelope.date.clone(), + } + } +} impl Table for Envelope { fn head() -> Row { @@ -14,15 +53,29 @@ impl Table for Envelope { fn row(&self) -> Row { let id = self.id.to_string(); - let flags = self.flags.to_symbols_string(); let unseen = !self.flags.contains(&Flag::Seen); + let flags = { + let mut flags = String::new(); + flags.push_str(if !unseen { " " } else { "āœ·" }); + flags.push_str(if self.flags.contains(&Flag::Answered) { + "ā†µ" + } else { + " " + }); + flags.push_str(if self.flags.contains(&Flag::Flagged) { + "āš‘" + } else { + " " + }); + flags + }; let subject = &self.subject; let sender = if let Some(name) = &self.from.name { name } else { &self.from.addr }; - let date = self.date.format("%d/%m/%Y %H:%M").to_string(); + let date = self.date.to_rfc3339(); Row::new() .cell(Cell::new(id).bold_if(unseen).red()) diff --git a/src/domain/envelope/envelopes.rs b/src/domain/envelope/envelopes.rs index 1bbaa31..1842e8b 100644 --- a/src/domain/envelope/envelopes.rs +++ b/src/domain/envelope/envelopes.rs @@ -1,11 +1,32 @@ +use std::ops; + use anyhow::Result; -use himalaya_lib::Envelopes; +use serde::Serialize; use crate::{ printer::{PrintTable, PrintTableOpts, WriteColor}, ui::Table, + Envelope, }; +/// Represents the list of envelopes. +#[derive(Clone, Debug, Default, Serialize)] +pub struct Envelopes(Vec); + +impl ops::Deref for Envelopes { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for Envelopes { + fn from(envelopes: himalaya_lib::Envelopes) -> Self { + Envelopes(envelopes.iter().map(Envelope::from).collect()) + } +} + impl PrintTable for Envelopes { fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> { writeln!(writer)?; diff --git a/src/domain/flag/args.rs b/src/domain/flag/args.rs index 8c476f8..5a660a0 100644 --- a/src/domain/flag/args.rs +++ b/src/domain/flag/args.rs @@ -83,7 +83,11 @@ pub fn flags_arg() -> Arg { Arg::new(ARG_FLAGS) .value_name("FLAGS") .help("The flags") - .long_help("The list of flags. It can be one of: seen, answered, flagged, deleted, draft, recent. Other flags are considered custom.") + .long_help( + "The list of flags. +It can be one of: seen, answered, flagged, deleted, or draft. +Other flags are considered custom.", + ) .num_args(1..) .required(true) .last(true) diff --git a/src/domain/flag/flag.rs b/src/domain/flag/flag.rs new file mode 100644 index 0000000..d9f2832 --- /dev/null +++ b/src/domain/flag/flag.rs @@ -0,0 +1,25 @@ +use serde::Serialize; + +/// Represents the flag variants. +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize)] +pub enum Flag { + Seen, + Answered, + Flagged, + Deleted, + Draft, + Custom(String), +} + +impl From<&himalaya_lib::Flag> for Flag { + fn from(flag: &himalaya_lib::Flag) -> Self { + match flag { + himalaya_lib::Flag::Seen => Flag::Seen, + himalaya_lib::Flag::Answered => Flag::Answered, + himalaya_lib::Flag::Flagged => Flag::Flagged, + himalaya_lib::Flag::Deleted => Flag::Deleted, + himalaya_lib::Flag::Draft => Flag::Draft, + himalaya_lib::Flag::Custom(flag) => Flag::Custom(flag.clone()), + } + } +} diff --git a/src/domain/flag/flags.rs b/src/domain/flag/flags.rs new file mode 100644 index 0000000..b413526 --- /dev/null +++ b/src/domain/flag/flags.rs @@ -0,0 +1,21 @@ +use serde::Serialize; +use std::{collections::HashSet, ops}; + +use crate::Flag; + +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)] +pub struct Flags(pub HashSet); + +impl ops::Deref for Flags { + type Target = HashSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for Flags { + fn from(flags: himalaya_lib::Flags) -> Self { + Flags(flags.iter().map(Flag::from).collect()) + } +} diff --git a/src/domain/flag/mod.rs b/src/domain/flag/mod.rs index b0b957b..5d92934 100644 --- a/src/domain/flag/mod.rs +++ b/src/domain/flag/mod.rs @@ -1,2 +1,8 @@ pub mod args; pub mod handlers; + +pub mod flag; +pub use flag::*; + +pub mod flags; +pub use flags::*; diff --git a/src/domain/folder/folder.rs b/src/domain/folder/folder.rs index ba0d931..8e201d2 100644 --- a/src/domain/folder/folder.rs +++ b/src/domain/folder/folder.rs @@ -1,7 +1,24 @@ -use himalaya_lib::folder::Folder; +use serde::Serialize; use crate::ui::{Cell, Row, Table}; +#[derive(Clone, Debug, Default, Serialize)] +pub struct Folder { + pub delim: String, + pub name: String, + pub desc: String, +} + +impl From<&himalaya_lib::Folder> for Folder { + fn from(folder: &himalaya_lib::Folder) -> Self { + Folder { + delim: folder.delim.clone(), + name: folder.name.clone(), + desc: folder.desc.clone(), + } + } +} + impl Table for Folder { fn head() -> Row { Row::new() diff --git a/src/domain/folder/folders.rs b/src/domain/folder/folders.rs index db34dad..93426d8 100644 --- a/src/domain/folder/folders.rs +++ b/src/domain/folder/folders.rs @@ -1,11 +1,31 @@ +use std::ops; + use anyhow::Result; -use himalaya_lib::folder::Folders; +use serde::Serialize; use crate::{ printer::{PrintTable, PrintTableOpts, WriteColor}, ui::Table, + Folder, }; +#[derive(Clone, Debug, Default, Serialize)] +pub struct Folders(Vec); + +impl ops::Deref for Folders { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for Folders { + fn from(folders: himalaya_lib::Folders) -> Self { + Folders(folders.iter().map(Folder::from).collect()) + } +} + impl PrintTable for Folders { fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> { writeln!(writer)?; diff --git a/src/domain/folder/handlers.rs b/src/domain/folder/handlers.rs index 85c1516..3fd8e9b 100644 --- a/src/domain/folder/handlers.rs +++ b/src/domain/folder/handlers.rs @@ -5,7 +5,10 @@ use anyhow::Result; use himalaya_lib::{AccountConfig, Backend}; -use crate::printer::{PrintTableOpts, Printer}; +use crate::{ + printer::{PrintTableOpts, Printer}, + Folders, +}; pub fn expunge( folder: &str, @@ -22,7 +25,7 @@ pub fn list( printer: &mut P, backend: &mut B, ) -> Result<()> { - let folders = backend.list_folders()?; + let folders: Folders = backend.list_folders()?.into(); printer.print_table( // TODO: remove Box Box::new(folders), From 5734b30fd149d3c3b48783dc67feddd2cd1871d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Mon, 20 Feb 2023 17:47:40 +0100 Subject: [PATCH 08/19] fix config unit tests --- src/config/config.rs | 137 ++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 61 deletions(-) diff --git a/src/config/config.rs b/src/config/config.rs index 1d7744a..ccc23cf 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -159,10 +159,11 @@ mod tests { fn account_missing_backend_field() { let config = make_config("[account]"); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `backend` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `backend`")); } #[test] @@ -176,7 +177,7 @@ mod tests { .unwrap_err() .root_cause() .to_string() - .starts_with("unknown variant `bad`")); + .contains("unknown variant `bad`")); } #[test] @@ -186,10 +187,11 @@ mod tests { backend = \"none\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `email` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `email`")); } #[test] @@ -201,10 +203,11 @@ mod tests { backend = \"imap\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `imap-host` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `imap-host`")); } #[test] @@ -217,10 +220,11 @@ mod tests { imap-host = \"localhost\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `imap-port` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `imap-port`")); } #[test] @@ -234,10 +238,11 @@ mod tests { imap-port = 993", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `imap-login` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `imap-login`")); } #[test] @@ -252,10 +257,11 @@ mod tests { imap-login = \"login\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `imap-passwd-cmd` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `imap-passwd-cmd`")); } #[test] @@ -267,10 +273,11 @@ mod tests { backend = \"maildir\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `maildir-root-dir` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `maildir-root-dir`")); } #[cfg(feature = "notmuch-backend")] @@ -283,10 +290,11 @@ mod tests { backend = \"notmuch\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `notmuch-db-path` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `notmuch-db-path`")); } #[test] @@ -297,10 +305,11 @@ mod tests { backend = \"none\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `sender` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `sender`")); } #[test] @@ -312,10 +321,11 @@ mod tests { sender = \"bad\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "unknown variant `bad`, expected one of `none`, `smtp`, `sendmail` at line 1 column 1", - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("unknown variant `bad`, expected one of `none`, `smtp`, `sendmail`"),); } #[test] @@ -327,10 +337,11 @@ mod tests { sender = \"smtp\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `smtp-host` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `smtp-host`")); } #[test] @@ -343,10 +354,11 @@ mod tests { smtp-host = \"localhost\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `smtp-port` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `smtp-port`")); } #[test] @@ -360,10 +372,11 @@ mod tests { smtp-port = 25", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `smtp-login` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `smtp-login`")); } #[test] @@ -378,10 +391,11 @@ mod tests { smtp-login = \"login\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `smtp-passwd-cmd` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `smtp-passwd-cmd`")); } #[test] @@ -393,10 +407,11 @@ mod tests { sender = \"sendmail\"", ); - assert_eq!( - config.unwrap_err().root_cause().to_string(), - "missing field `sendmail-cmd` at line 1 column 1" - ); + assert!(config + .unwrap_err() + .root_cause() + .to_string() + .contains("missing field `sendmail-cmd`")); } #[test] From 21d8d57f72e3fc4571cc2e5dbf418bd6f9e0c1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Mon, 20 Feb 2023 18:26:10 +0100 Subject: [PATCH 09/19] add create and delete folder commands #54 --- CHANGELOG.md | 6 ++++++ src/domain/folder/args.rs | 16 ++++++++++++++++ src/domain/folder/handlers.rs | 33 +++++++++++++++++++++++++++++++-- src/main.rs | 30 +++++++++++++++++++++++++----- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8afdb04..d32b16c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added `create` and `delete` folder commands [sourcehut#54]. + ### Fixed - Fixed config deserialization issue with `email-hooks` and @@ -670,3 +674,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#356]: https://github.com/soywod/himalaya/issues/356 [#419]: https://github.com/soywod/himalaya/issues/419 [#430]: https://github.com/soywod/himalaya/issues/430 + +[sourcehut#54]: https://todo.sr.ht/~soywod/pimalaya/54 diff --git a/src/domain/folder/args.rs b/src/domain/folder/args.rs index 4ddf949..e55c08f 100644 --- a/src/domain/folder/args.rs +++ b/src/domain/folder/args.rs @@ -11,6 +11,8 @@ use crate::ui::table; const ARG_SOURCE: &str = "source"; const ARG_TARGET: &str = "target"; +const CMD_CREATE: &str = "create"; +const CMD_DELETE: &str = "delete"; const CMD_EXPUNGE: &str = "expunge"; const CMD_FOLDERS: &str = "folders"; const CMD_LIST: &str = "list"; @@ -18,8 +20,10 @@ const CMD_LIST: &str = "list"; /// Represents the folder commands. #[derive(Debug, PartialEq, Eq)] pub enum Cmd { + Create, List(table::args::MaxTableWidth), Expunge, + Delete, } /// Represents the folder command matcher. @@ -28,10 +32,16 @@ pub fn matches(m: &ArgMatches) -> Result> { if let Some(_) = m.subcommand_matches(CMD_EXPUNGE) { info!("expunge folder subcommand matched"); Some(Cmd::Expunge) + } else if let Some(_) = m.subcommand_matches(CMD_CREATE) { + debug!("create folder command matched"); + Some(Cmd::Create) } else if let Some(m) = m.subcommand_matches(CMD_LIST) { debug!("list folders command matched"); let max_table_width = table::args::parse_max_width(m); Some(Cmd::List(max_table_width)) + } else if let Some(_) = m.subcommand_matches(CMD_DELETE) { + debug!("delete folder command matched"); + Some(Cmd::Delete) } else { info!("no folder subcommand matched, falling back to subcommand list"); Some(Cmd::List(None)) @@ -49,9 +59,15 @@ pub fn subcmd() -> Command { .about("Manage folders") .subcommands([ Command::new(CMD_EXPUNGE).about("Delete emails marked for deletion"), + Command::new(CMD_CREATE) + .aliases(["add", "new"]) + .about("Create a new folder"), Command::new(CMD_LIST) .about("List folders") .arg(table::args::max_width()), + Command::new(CMD_DELETE) + .aliases(["remove", "rm"]) + .about("Delete a folder with all its emails"), ]) } diff --git a/src/domain/folder/handlers.rs b/src/domain/folder/handlers.rs index 3fd8e9b..dc7b7f4 100644 --- a/src/domain/folder/handlers.rs +++ b/src/domain/folder/handlers.rs @@ -3,7 +3,9 @@ //! This module gathers all folder actions triggered by the CLI. use anyhow::Result; +use dialoguer::Confirm; use himalaya_lib::{AccountConfig, Backend}; +use std::process; use crate::{ printer::{PrintTableOpts, Printer}, @@ -11,19 +13,19 @@ use crate::{ }; pub fn expunge( - folder: &str, printer: &mut P, backend: &mut B, + folder: &str, ) -> Result<()> { backend.expunge_folder(folder)?; printer.print(format!("Folder {folder} successfully expunged!")) } pub fn list( - max_width: Option, config: &AccountConfig, printer: &mut P, backend: &mut B, + max_width: Option, ) -> Result<()> { let folders: Folders = backend.list_folders()?.into(); printer.print_table( @@ -36,6 +38,33 @@ pub fn list( ) } +pub fn create( + printer: &mut P, + backend: &mut B, + folder: &str, +) -> Result<()> { + backend.add_folder(folder)?; + printer.print("Folder successfully created!") +} + +pub fn delete( + printer: &mut P, + backend: &mut B, + folder: &str, +) -> Result<()> { + if let Some(false) | None = Confirm::new() + .with_prompt(format!("Confirm deletion of folder {folder}?")) + .default(false) + .report(false) + .interact_opt()? + { + process::exit(0); + }; + + backend.delete_folder(folder)?; + printer.print("Folder successfully deleted!") +} + #[cfg(test)] mod tests { use himalaya_lib::{ diff --git a/src/main.rs b/src/main.rs index 797af9b..8b83d47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{anyhow, Context, Result}; use clap::Command; use std::{borrow::Cow, env}; use url::Url; @@ -147,24 +147,44 @@ fn main() -> Result<()> { // checks folder commands match folder::args::matches(&m)? { - Some(folder::args::Cmd::Expunge) => { - let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?; + Some(folder::args::Cmd::Create) => { + let folder = folder + .ok_or_else(|| anyhow!("the folder argument is missing")) + .context("cannot create folder")?; + let folder = account_config.folder_alias(folder)?; let mut backend = BackendBuilder::new() .disable_cache(disable_cache) .build(&account_config, &backend_config)?; - return folder::handlers::expunge(&folder, &mut printer, backend.as_mut()); + return folder::handlers::create(&mut printer, backend.as_mut(), &folder); } Some(folder::args::Cmd::List(max_width)) => { let mut backend = BackendBuilder::new() .disable_cache(disable_cache) .build(&account_config, &backend_config)?; return folder::handlers::list( - max_width, &account_config, &mut printer, backend.as_mut(), + max_width, ); } + Some(folder::args::Cmd::Expunge) => { + let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?; + let mut backend = BackendBuilder::new() + .disable_cache(disable_cache) + .build(&account_config, &backend_config)?; + return folder::handlers::expunge(&mut printer, backend.as_mut(), &folder); + } + Some(folder::args::Cmd::Delete) => { + let folder = folder + .ok_or_else(|| anyhow!("the folder argument is missing")) + .context("cannot delete folder")?; + let folder = account_config.folder_alias(folder)?; + let mut backend = BackendBuilder::new() + .disable_cache(disable_cache) + .build(&account_config, &backend_config)?; + return folder::handlers::delete(&mut printer, backend.as_mut(), &folder); + } _ => (), } From 22fb1b8deecfb0aac6f637d60d08a5bc6d390fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Tue, 21 Feb 2023 16:06:58 +0100 Subject: [PATCH 10/19] add completions and man pages to release archives #43 --- .github/workflows/deployment.yml | 20 ++++++++++++++++++-- CHANGELOG.md | 3 +++ src/main.rs | 3 +-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 1e3d1f4..bb3461c 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -54,10 +54,26 @@ jobs: args: --release - name: Compress executable (unix) if: matrix.os_name == 'linux' || matrix.os_name == 'macos' - run: tar czf himalaya.tar.gz -C target/release himalaya + run: | + mkdir -p target/release/{man,completions} + target/release/himalaya man target/release/man + target/release/himalaya completion bash > target/release/completions/himalaya.bash + target/release/himalaya completion elvish > target/release/completions/himalaya.elvish + target/release/himalaya completion fish > target/release/completions/himalaya.fish + target/release/himalaya completion powershell > target/release/completions/himalaya.powershell + target/release/himalaya completion zsh > target/release/completions/himalaya.zsh + tar czf himalaya.tar.gz -C target/release himalaya man completions - name: Compress executable (windows) if: matrix.os_name == 'windows' - run: tar czf himalaya.tar.gz -C target/release himalaya.exe + run: | + mkdir -p target/release/{man,completions} + target/release/himalaya.exe man target/release/man + target/release/himalaya.exe completion bash > target/release/completions/himalaya.bash + target/release/himalaya.exe completion elvish > target/release/completions/himalaya.elvish + target/release/himalaya.exe completion fish > target/release/completions/himalaya.fish + target/release/himalaya.exe completion powershell > target/release/completions/himalaya.powershell + target/release/himalaya.exe completion zsh > target/release/completions/himalaya.zsh + tar czf himalaya.tar.gz -C target/release himalaya.exe man completions - name: Upload release asset uses: actions/upload-release-asset@v1 env: diff --git a/CHANGELOG.md b/CHANGELOG.md index d32b16c..e9c0353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added `create` and `delete` folder commands [sourcehut#54]. +- Added generated completions and man pages to releases + [sourcehut#43]. ### Fixed @@ -675,4 +677,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#419]: https://github.com/soywod/himalaya/issues/419 [#430]: https://github.com/soywod/himalaya/issues/430 +[sourcehut#43]: https://todo.sr.ht/~soywod/pimalaya/43 [sourcehut#54]: https://todo.sr.ht/~soywod/pimalaya/54 diff --git a/src/main.rs b/src/main.rs index 8b83d47..320f5e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,8 +77,7 @@ fn main() -> Result<()> { _ => (), } - // checks completion command before configs - // https://github.com/soywod/himalaya/issues/115 + // also checks man command before configs match man::args::matches(&m)? { Some(man::args::Cmd::GenerateAll(dir)) => { return man::handlers::generate(dir, create_app()); From fb324878fa5c4f34d111d39b8b37a854e3b48c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Wed, 22 Feb 2023 13:14:21 +0100 Subject: [PATCH 11/19] improve global options, add account config `sync-folders-strategy` --- CHANGELOG.md | 29 +++++++++++++ Cargo.lock | 2 +- config.sample.toml | 3 +- src/cache/args.rs | 7 +++- src/config/args.rs | 3 +- src/config/prelude.rs | 20 +++++++-- src/domain/account/args.rs | 33 +++++++++++++-- src/domain/account/config.rs | 11 +++-- src/domain/account/handlers.rs | 15 ++++--- src/domain/folder/args.rs | 74 +++++++++++++++++++++++++++++++++- src/main.rs | 8 +--- src/man/args.rs | 9 +++-- src/output/args.rs | 23 ++++++----- 13 files changed, 194 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9c0353..78629b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `create` and `delete` folder commands [sourcehut#54]. - Added generated completions and man pages to releases [sourcehut#43]. +- Added new account config option `sync-folders-strategy` which allows + to choose a folders synchronization strategy [sourcehut#59]: + + - `sync-folders-strategy = "all"`: synchronize all existing folders + for the current account + - `sync-folders-strategy.include = ["folder1", "folder2", ā€¦]`: + synchronize only the given folders for the current account + - `sync-folders-strategy.exclude = ["folder1", "folder2", ā€¦]`: + synchronizes all folders except the given ones for the current + account + + Also added new `account sync` arguments that override the account + config option: + + - `-A|--all-folders`: include all folders to the synchronization. + - `-F|--include-folder`: include given folders to the + synchronization. They can be repeated `-F folder1 folder2` or `-F + folder1 -F folder2`. + - `-x|--exclude-folder`: exclude given folders from the + synchronization. They can be repeated `-x folder1 folder2` or `-x + folder1 -F folder2`. + +### Changed + +- Made global options truly global, which means they can be used + everywhere (not only *before* commands but also *after*) + [sourcehut#60]. ### Fixed @@ -679,3 +706,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [sourcehut#43]: https://todo.sr.ht/~soywod/pimalaya/43 [sourcehut#54]: https://todo.sr.ht/~soywod/pimalaya/54 +[sourcehut#59]: https://todo.sr.ht/~soywod/pimalaya/59 +[sourcehut#60]: https://todo.sr.ht/~soywod/pimalaya/60 diff --git a/Cargo.lock b/Cargo.lock index b152a64..affed63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -804,7 +804,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#26d3b9e74c978f6dc94689bff809d48fe5ba4c85" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#9617be67bcec1f1a80924288be34d3476a260890" dependencies = [ "ammonia", "chrono", diff --git a/config.sample.toml b/config.sample.toml index a18f3a8..8870953 100644 --- a/config.sample.toml +++ b/config.sample.toml @@ -11,7 +11,7 @@ email-writing-sign-cmd = "gpg -o - -saq" email-writing-encrypt-cmd = "gpg -o - -eqar " [example] -default = false +default = true display-name = "Display NAME (gmail)" email = "display.name@gmail.local" @@ -36,6 +36,7 @@ smtp-starttls = false sync = true sync-dir = "/tmp/sync/gmail" +sync-folders-strategy.only = ["INBOX"] [example.folder-aliases] inbox = "INBOX" diff --git a/src/cache/args.rs b/src/cache/args.rs index 9da7989..cd40a09 100644 --- a/src/cache/args.rs +++ b/src/cache/args.rs @@ -8,8 +8,13 @@ const ARG_DISABLE_CACHE: &str = "disable-cache"; /// the user to disable any sort of cache. pub fn arg() -> Arg { Arg::new(ARG_DISABLE_CACHE) - .long("disable-cache") .help("Disable any sort of cache") + .long_help( + "Disable any sort of cache. The action depends on +the command it applies on.", + ) + .long("disable-cache") + .global(true) .action(ArgAction::SetTrue) } diff --git a/src/config/args.rs b/src/config/args.rs index 20ba201..ec425f5 100644 --- a/src/config/args.rs +++ b/src/config/args.rs @@ -8,9 +8,10 @@ const ARG_CONFIG: &str = "config"; /// user to customize the config file path. pub fn arg() -> Arg { Arg::new(ARG_CONFIG) + .help("Set a custom configuration file path") .long("config") .short('c') - .help("Forces a specific config file path") + .global(true) .value_name("PATH") } diff --git a/src/config/prelude.rs b/src/config/prelude.rs index 8d4f830..82f5528 100644 --- a/src/config/prelude.rs +++ b/src/config/prelude.rs @@ -1,9 +1,9 @@ -use serde::{Deserialize, Serialize}; -use std::path::PathBuf; - use himalaya_lib::{ - EmailHooks, EmailSender, EmailTextPlainFormat, MaildirConfig, SendmailConfig, SmtpConfig, + folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat, + MaildirConfig, SendmailConfig, SmtpConfig, }; +use serde::{Deserialize, Serialize}; +use std::{collections::HashSet, path::PathBuf}; #[cfg(feature = "imap-backend")] use himalaya_lib::ImapConfig; @@ -111,3 +111,15 @@ pub struct EmailHooksDef { /// Represents the hook called just before sending an email. pub pre_send: Option, } + +#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "SyncFoldersStrategy", rename_all = "kebab-case")] +pub enum SyncFoldersStrategyDef { + #[default] + All, + #[serde(alias = "only")] + Include(HashSet), + #[serde(alias = "except")] + #[serde(alias = "ignore")] + Exclude(HashSet), +} diff --git a/src/domain/account/args.rs b/src/domain/account/args.rs index 701552b..7449f74 100644 --- a/src/domain/account/args.rs +++ b/src/domain/account/args.rs @@ -2,9 +2,11 @@ use anyhow::Result; use clap::{Arg, ArgAction, ArgMatches, Command}; +use himalaya_lib::folder::sync::Strategy as SyncFoldersStrategy; use log::info; +use std::collections::HashSet; -use crate::ui::table; +use crate::{folder, ui::table}; const ARG_ACCOUNT: &str = "account"; const ARG_DRY_RUN: &str = "dry-run"; @@ -20,7 +22,7 @@ pub enum Cmd { /// Represents the list accounts command. List(table::args::MaxTableWidth), /// Represents the sync account command. - Sync(DryRun), + Sync(Option, DryRun), } /// Represents the account command matcher. @@ -29,7 +31,22 @@ pub fn matches(m: &ArgMatches) -> Result> { if let Some(m) = m.subcommand_matches(CMD_SYNC) { info!("sync account subcommand matched"); let dry_run = parse_dry_run_arg(m); - Some(Cmd::Sync(dry_run)) + let include = folder::args::parse_include_arg(m); + let exclude = folder::args::parse_exclude_arg(m); + let folders_strategy = if let Some(folder) = folder::args::parse_source_arg(m) { + Some(SyncFoldersStrategy::Include(HashSet::from_iter([ + folder.to_owned() + ]))) + } else if !include.is_empty() { + Some(SyncFoldersStrategy::Include(include.to_owned())) + } else if !exclude.is_empty() { + Some(SyncFoldersStrategy::Exclude(exclude)) + } else if folder::args::parse_all_arg(m) { + Some(SyncFoldersStrategy::All) + } else { + None + }; + Some(Cmd::Sync(folders_strategy, dry_run)) } else if let Some(m) = m.subcommand_matches(CMD_LIST) { info!("list accounts subcommand matched"); let max_table_width = table::args::parse_max_width(m); @@ -55,6 +72,13 @@ pub fn subcmd() -> Command { .arg(table::args::max_width()), Command::new(CMD_SYNC) .about("Synchronize the given account locally") + .arg(folder::args::all_arg("Synchronize all folders")) + .arg(folder::args::include_arg( + "Synchronize only the given folders", + )) + .arg(folder::args::exclude_arg( + "Synchronize all folders except the given ones", + )) .arg(dry_run()), ]) } @@ -63,9 +87,10 @@ pub fn subcmd() -> Command { /// the user to select a different account than the default one. pub fn arg() -> Arg { Arg::new(ARG_ACCOUNT) + .help("Set the account") .long("account") .short('a') - .help("Select a specific account by name") + .global(true) .value_name("STRING") } diff --git a/src/domain/account/config.rs b/src/domain/account/config.rs index 046d7e8..6086dbb 100644 --- a/src/domain/account/config.rs +++ b/src/domain/account/config.rs @@ -4,8 +4,11 @@ //! account in the accounts section of the user configuration file. use himalaya_lib::{ - AccountConfig, BackendConfig, EmailHooks, EmailSender, EmailTextPlainFormat, MaildirConfig, + folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, BackendConfig, EmailHooks, + EmailSender, EmailTextPlainFormat, MaildirConfig, }; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, path::PathBuf}; #[cfg(feature = "imap-backend")] use himalaya_lib::ImapConfig; @@ -13,9 +16,6 @@ use himalaya_lib::ImapConfig; #[cfg(feature = "notmuch-backend")] use himalaya_lib::NotmuchConfig; -use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, path::PathBuf}; - use crate::config::{prelude::*, DeserializedConfig}; /// Represents all existing kind of account config. @@ -104,6 +104,8 @@ pub struct DeserializedBaseAccountConfig { #[serde(default)] pub sync: bool, pub sync_dir: Option, + #[serde(default, with = "SyncFoldersStrategyDef")] + pub sync_folders_strategy: SyncFoldersStrategy, } impl DeserializedBaseAccountConfig { @@ -207,6 +209,7 @@ impl DeserializedBaseAccountConfig { }, sync: self.sync, sync_dir: self.sync_dir.clone(), + sync_folders_strategy: self.sync_folders_strategy.clone(), } } } diff --git a/src/domain/account/handlers.rs b/src/domain/account/handlers.rs index 0f5aeca..442ad04 100644 --- a/src/domain/account/handlers.rs +++ b/src/domain/account/handlers.rs @@ -3,7 +3,10 @@ //! This module gathers all account actions triggered by the CLI. use anyhow::Result; -use himalaya_lib::{AccountConfig, Backend, BackendSyncBuilder, BackendSyncProgressEvent}; +use himalaya_lib::{ + folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, Backend, BackendSyncBuilder, + BackendSyncProgressEvent, +}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use log::{info, trace}; @@ -43,15 +46,17 @@ pub fn sync( account_config: &AccountConfig, printer: &mut P, backend: &dyn Backend, - folder: &Option, + folders_strategy: Option, dry_run: bool, ) -> Result<()> { info!("entering the sync accounts handler"); - trace!("dry run: {}", dry_run); + trace!("dry run: {dry_run}"); + trace!("folders strategy: {folders_strategy:#?}"); let mut sync_builder = BackendSyncBuilder::new(account_config); - if let Some(folder) = folder { - sync_builder = sync_builder.only_folder(folder); + + if let Some(strategy) = folders_strategy { + sync_builder = sync_builder.folders_strategy(strategy); } if dry_run { diff --git a/src/domain/folder/args.rs b/src/domain/folder/args.rs index e55c08f..f83b28f 100644 --- a/src/domain/folder/args.rs +++ b/src/domain/folder/args.rs @@ -3,12 +3,17 @@ //! This module provides subcommands, arguments and a command matcher //! related to the folder domain. +use std::collections::HashSet; + use anyhow::Result; -use clap::{self, Arg, ArgMatches, Command}; +use clap::{self, Arg, ArgAction, ArgMatches, Command}; use log::{debug, info}; use crate::ui::table; +const ARG_ALL: &str = "all"; +const ARG_EXCLUDE: &str = "exclude"; +const ARG_INCLUDE: &str = "include"; const ARG_SOURCE: &str = "source"; const ARG_TARGET: &str = "target"; const CMD_CREATE: &str = "create"; @@ -74,9 +79,10 @@ pub fn subcmd() -> Command { /// Represents the source folder argument. pub fn source_arg() -> Arg { Arg::new(ARG_SOURCE) + .help("Set the source folder") .long("folder") .short('f') - .help("Specifies the source folder") + .global(true) .value_name("SOURCE") } @@ -85,6 +91,70 @@ pub fn parse_source_arg(matches: &ArgMatches) -> Option<&str> { matches.get_one::(ARG_SOURCE).map(String::as_str) } +/// Represents the all folders argument. +pub fn all_arg(help: &'static str) -> Arg { + Arg::new(ARG_ALL) + .help(help) + .long("all-folders") + .alias("all") + .short('A') + .action(ArgAction::SetTrue) + .conflicts_with(ARG_SOURCE) + .conflicts_with(ARG_INCLUDE) + .conflicts_with(ARG_EXCLUDE) +} + +/// Represents the all folders argument parser. +pub fn parse_all_arg(m: &ArgMatches) -> bool { + m.get_flag(ARG_ALL) +} + +/// Represents the folders to include argument. +pub fn include_arg(help: &'static str) -> Arg { + Arg::new(ARG_INCLUDE) + .help(help) + .long("include-folder") + .alias("only") + .short('F') + .value_name("FOLDER") + .num_args(1..) + .action(ArgAction::Append) + .conflicts_with(ARG_SOURCE) + .conflicts_with(ARG_ALL) + .conflicts_with(ARG_EXCLUDE) +} + +/// Represents the folders to include argument parser. +pub fn parse_include_arg(m: &ArgMatches) -> HashSet { + m.get_many::(ARG_INCLUDE) + .unwrap_or_default() + .map(ToOwned::to_owned) + .collect() +} + +/// Represents the folders to exclude argument. +pub fn exclude_arg(help: &'static str) -> Arg { + Arg::new(ARG_EXCLUDE) + .help(help) + .long("exclude-folder") + .alias("except") + .short('x') + .value_name("FOLDER") + .num_args(1..) + .action(ArgAction::Append) + .conflicts_with(ARG_SOURCE) + .conflicts_with(ARG_ALL) + .conflicts_with(ARG_INCLUDE) +} + +/// Represents the folders to exclude argument parser. +pub fn parse_exclude_arg(m: &ArgMatches) -> HashSet { + m.get_many::(ARG_EXCLUDE) + .unwrap_or_default() + .map(ToOwned::to_owned) + .collect() +} + /// Represents the target folder argument. pub fn target_arg() -> Arg { Arg::new(ARG_TARGET) diff --git a/src/main.rs b/src/main.rs index 320f5e0..bfd2ac4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -122,11 +122,7 @@ fn main() -> Result<()> { Some(account::args::Cmd::List(max_width)) => { return account::handlers::list(max_width, &account_config, &config, &mut printer); } - Some(account::args::Cmd::Sync(dry_run)) => { - let folder = match folder { - Some(folder) => Some(account_config.folder_alias(folder)?), - None => None, - }; + Some(account::args::Cmd::Sync(folders_strategy, dry_run)) => { let backend = BackendBuilder::new() .sessions_pool_size(8) .disable_cache(true) @@ -135,7 +131,7 @@ fn main() -> Result<()> { &account_config, &mut printer, backend.as_ref(), - &folder, + folders_strategy, dry_run, )?; backend.close()?; diff --git a/src/man/args.rs b/src/man/args.rs index 6361c47..a85f953 100644 --- a/src/man/args.rs +++ b/src/man/args.rs @@ -30,11 +30,14 @@ pub fn matches(m: &ArgMatches) -> Result> { /// Man subcommands. pub fn subcmd() -> Command { Command::new(CMD_MAN) - .about("Generates all man pages to the specified directory.") + .about("Generate all man pages to the given directory") .arg( Arg::new(ARG_DIR) - .help("Directory where to generate man files") - .long_help("Represents the directory where all man files of all commands and subcommands should be generated in.") + .help("Directory to generate man files in") + .long_help( + "Represents the directory where all man files of +all commands and subcommands should be generated in.", + ) .required(true), ) } diff --git a/src/output/args.rs b/src/output/args.rs index aa5776a..d5a98a1 100644 --- a/src/output/args.rs +++ b/src/output/args.rs @@ -11,22 +11,23 @@ pub(crate) const ARG_OUTPUT: &str = "output"; pub fn args() -> Vec { vec![ Arg::new(ARG_OUTPUT) - .help("Defines the output format") + .help("Set the output format") .long("output") .short('o') + .global(true) .value_name("FMT") .value_parser(["plain", "json"]) .default_value("plain"), Arg::new(ARG_COLOR) - .help("Controls when to use colors.") + .help("Control when to use colors.") .long_help( - " -This flag controls when to use colors. The default setting is 'auto', which -means himalaya will try to guess when to use colors. For example, if himalaya is -printing to a terminal, then it will use colors, but if it is redirected to a -file or a pipe, then it will suppress color output. himalaya will suppress color -output in some other circumstances as well. For example, if the TERM -environment variable is not set or set to 'dumb', then himalaya will not use + "This flag controls when to use colors. The default +setting is 'auto', which means himalaya will try to guess when to use +colors. For example, if himalaya is printing to a terminal, then it +will use colors, but if it is redirected to a file or a pipe, then it +will suppress color output. himalaya will suppress color output in +some other circumstances as well. For example, if the TERM environment +variable is not set or set to 'dumb', then himalaya will not use colors. The possible values for this flag are: @@ -34,11 +35,11 @@ The possible values for this flag are: never Colors will never be used. auto The default. himalaya tries to be smart. always Colors will always be used regardless of where output is sent. -ansi Like 'always', but emits ANSI escapes (even in a Windows console). -", +ansi Like 'always', but emits ANSI escapes (even in a Windows console).", ) .long("color") .short('C') + .global(true) .value_parser(["never", "auto", "always", "ansi"]) .default_value("auto") .value_name("WHEN"), From 55f5de1803195c9d50fefc817d51771b14e5368d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Wed, 22 Feb 2023 14:36:31 +0100 Subject: [PATCH 12/19] replace reply all -a by -A --- CHANGELOG.md | 2 ++ src/domain/email/args.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78629b2..9f6332f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Made global options truly global, which means they can be used everywhere (not only *before* commands but also *after*) [sourcehut#60]. +- Replaced reply all `-a` argument with `-A` because it conflicted + with the global option `-a|--account`. ### Fixed diff --git a/src/domain/email/args.rs b/src/domain/email/args.rs index 8a3d5f8..ab4f207 100644 --- a/src/domain/email/args.rs +++ b/src/domain/email/args.rs @@ -298,9 +298,9 @@ pub fn parse_criteria_arg(matches: &ArgMatches) -> String { /// Represents the email reply all argument. pub fn reply_all_flag() -> Arg { Arg::new(ARG_REPLY_ALL) - .help("Includes all recipients") + .help("Include all recipients") .long("all") - .short('a') + .short('A') .action(ArgAction::SetTrue) } From 501c7f18f545ceff4c133c07bf8bc15926987651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Thu, 23 Feb 2023 18:23:15 +0100 Subject: [PATCH 13/19] add flag seen by default for send and save commands --- Cargo.lock | 2 +- src/domain/email/handlers.rs | 8 ++++++-- src/ui/editor.rs | 8 ++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index affed63..dc0f31e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -804,7 +804,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#9617be67bcec1f1a80924288be34d3476a260890" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#3d71e3304eb529604f1059c54f8a2a214ab357dc" dependencies = [ "ammonia", "chrono", diff --git a/src/domain/email/handlers.rs b/src/domain/email/handlers.rs index c44a35e..20b1d2c 100644 --- a/src/domain/email/handlers.rs +++ b/src/domain/email/handlers.rs @@ -334,7 +334,7 @@ pub fn send( sender: &mut S, raw_email: String, ) -> Result<()> { - let folder = config.folder_alias("sent")?; + let folder = config.sent_folder_alias()?; let is_tty = atty::is(Stream::Stdin); let is_json = printer.is_json(); let raw_email = if is_tty || is_json { @@ -349,7 +349,11 @@ pub fn send( }; trace!("raw email: {:?}", raw_email); sender.send(raw_email.as_bytes())?; - backend.add_email(&folder, raw_email.as_bytes(), &Flags::default())?; + backend.add_email( + &folder, + raw_email.as_bytes(), + &Flags::from_iter([Flag::Seen]), + )?; Ok(()) } diff --git a/src/ui/editor.rs b/src/ui/editor.rs index e8da1eb..3ef83d5 100644 --- a/src/ui/editor.rs +++ b/src/ui/editor.rs @@ -81,7 +81,7 @@ pub fn edit_tpl_with_editor sender.send(&email)?; let sent_folder = config.sent_folder_alias()?; printer.print_log(format!("Adding email to the {} folderā€¦", sent_folder))?; - backend.add_email(&sent_folder, &email, &Flags::default())?; + backend.add_email(&sent_folder, &email, &Flags::from_iter([Flag::Seen]))?; remove_local_draft()?; printer.print("Done!")?; break; @@ -101,7 +101,11 @@ pub fn edit_tpl_with_editor .some_pgp_sign_cmd(config.email_writing_sign_cmd.as_ref()) .some_pgp_encrypt_cmd(config.email_writing_encrypt_cmd.as_ref()), )?; - backend.add_email(&draft_folder, &email, &Flags::from_iter([Flag::Draft]))?; + backend.add_email( + &draft_folder, + &email, + &Flags::from_iter([Flag::Seen, Flag::Draft]), + )?; remove_local_draft()?; printer.print(format!("Email successfully saved to {}", draft_folder))?; break; From d5efd03bcdf51feb69f91d74199c7de04a527084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Tue, 28 Feb 2023 02:16:24 +0100 Subject: [PATCH 14/19] bump himalaya lib 3aa70c4b --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index dc0f31e..e3af5b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -804,7 +804,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#3d71e3304eb529604f1059c54f8a2a214ab357dc" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#3aa70c4b48333aeb0088cc95d1bdfe0a50f34e23" dependencies = [ "ammonia", "chrono", From 69590f698604f1a3d5328dd624f6e1522eaf37e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Sat, 11 Mar 2023 17:33:57 +0100 Subject: [PATCH 15/19] added vendored cargo feature --- Cargo.lock | 12 +++++++++++- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3af5b4..4140dc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -804,7 +804,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#3aa70c4b48333aeb0088cc95d1bdfe0a50f34e23" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#43c2b5dbde3e6f6c2e76ad36b25d123ab3098b10" dependencies = [ "ammonia", "chrono", @@ -1383,6 +1383,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "111.25.0+1.1.1t" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3173cd3626c43e3854b1b727422a276e568d9ec5fe8cec197822cf52cfb743d6" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.78" @@ -1392,6 +1401,7 @@ dependencies = [ "autocfg", "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] diff --git a/Cargo.toml b/Cargo.toml index 7d47001..954cf14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ section = "mail" imap-backend = ["himalaya-lib/imap-backend"] smtp-sender = ["himalaya-lib/smtp-sender"] notmuch-backend = ["himalaya-lib/notmuch-backend"] +vendored = ["himalaya-lib/vendored"] default = ["imap-backend", "smtp-sender"] [dev-dependencies] @@ -38,7 +39,6 @@ email_address = "0.2.4" env_logger = "0.8" erased-serde = "0.3" himalaya-lib = { git = "https://git.sr.ht/~soywod/himalaya-lib", branch = "develop" } -# himalaya-lib = { path = "/home/soywod/sourcehut/himalaya-lib" } indicatif = "0.17" log = "0.4" once_cell = "1.16.0" From 7b3a9e4cc754e5781f39071fd0f0a263f0c69ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Wed, 29 Mar 2023 18:09:39 +0200 Subject: [PATCH 16/19] improve cargo features naming and organization --- Cargo.lock | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 17 ++++++-- 2 files changed, 134 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4140dc5..f5c8336 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -804,7 +804,7 @@ dependencies = [ [[package]] name = "himalaya-lib" version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#43c2b5dbde3e6f6c2e76ad36b25d123ab3098b10" +source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#7b8fb1d073b66d2f1d642df109c787ba3c31378f" dependencies = [ "ammonia", "chrono", @@ -822,18 +822,22 @@ dependencies = [ "mime-msg-builder", "native-tls", "notmuch", + "once_cell", "ouroboros", "proc-lock", "rayon", "regex", "rfc2047-decoder", "rusqlite", + "rustls", + "rustls-native-certs", "shellexpand", "thiserror", "tree_magic", "urlencoding", "utf7-imap", "uuid", + "webpki-roots", ] [[package]] @@ -937,6 +941,7 @@ dependencies = [ "nom 7.1.1", "ouroboros", "regex", + "rustls-connector", ] [[package]] @@ -1041,9 +1046,12 @@ dependencies = [ "nom 7.1.1", "once_cell", "quoted_printable", + "rustls", + "rustls-pemfile", "serde", "socket2", "tokio", + "webpki-roots", ] [[package]] @@ -1785,6 +1793,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "roff" version = "0.2.1" @@ -1819,6 +1842,51 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-connector" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6a18f8d10f71bce9bca6eaeb80429460e652f3bcf0381f0c5f8954abf7b3b8" +dependencies = [ + "log", + "rustls", + "rustls-native-certs", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.0", +] + [[package]] name = "ryu" version = "1.0.11" @@ -1847,6 +1915,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.7.0" @@ -1950,6 +2028,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "stacker" version = "0.1.15" @@ -2199,6 +2283,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.3.1" @@ -2326,6 +2416,35 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 954cf14..9c64cee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,22 @@ priority = "optional" section = "mail" [features] +default = ["imap-backend", "smtp-sender", "native-tls"] + +# backends imap-backend = ["himalaya-lib/imap-backend"] -smtp-sender = ["himalaya-lib/smtp-sender"] notmuch-backend = ["himalaya-lib/notmuch-backend"] -vendored = ["himalaya-lib/vendored"] -default = ["imap-backend", "smtp-sender"] + +# senders +smtp-sender = ["himalaya-lib/smtp-sender"] + +# native tls +native-tls = ["himalaya-lib/native-tls"] +native-tls-vendored = ["himalaya-lib/native-tls-vendored"] + +# rustls +rustls-tls = ["himalaya-lib/rustls-tls"] +rustls-native-certs = ["himalaya-lib/rustls-native-certs"] [dev-dependencies] tempfile = "3.3" From 072f488d8971f0b3a3f196a1d4a9d2c12a53edc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Thu, 20 Apr 2023 12:12:33 +0200 Subject: [PATCH 17/19] replace himalaya-lib by pimalaya-email --- CHANGELOG.md | 3 +- Cargo.lock | 82 ++++++++++++++++---------------- Cargo.toml | 23 ++++----- README.md | 40 ++++++++-------- src/config/config.rs | 8 ++-- src/config/prelude.rs | 6 +-- src/config/wizard/imap.rs | 2 +- src/config/wizard/maildir.rs | 2 +- src/config/wizard/notmuch.rs | 2 +- src/config/wizard/sendmail.rs | 2 +- src/config/wizard/smtp.rs | 2 +- src/domain/account/args.rs | 2 +- src/domain/account/config.rs | 6 +-- src/domain/account/handlers.rs | 8 ++-- src/domain/email/handlers.rs | 4 +- src/domain/envelope/envelope.rs | 4 +- src/domain/envelope/envelopes.rs | 4 +- src/domain/flag/args.rs | 2 +- src/domain/flag/flag.rs | 16 +++---- src/domain/flag/flags.rs | 4 +- src/domain/flag/handlers.rs | 2 +- src/domain/folder/folder.rs | 4 +- src/domain/folder/folders.rs | 4 +- src/domain/folder/handlers.rs | 4 +- src/domain/imap/handlers.rs | 2 +- src/domain/tpl/handlers.rs | 2 +- src/main.rs | 2 +- src/printer/print.rs | 2 +- src/printer/print_table.rs | 2 +- src/ui/editor.rs | 4 +- src/ui/table/table.rs | 2 +- 31 files changed, 128 insertions(+), 124 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f6332f..d667a1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [sourcehut#60]. - Replaced reply all `-a` argument with `-A` because it conflicted with the global option `-a|--account`. +- Replaced `himalaya-lib` by `pimalaya-email`. ### Fixed @@ -58,7 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Changed the location of the - [documentation](https://pimalaya.org/himalaya/docs/). + [documentation](https://pimalaya.org/himalaya/). ### Fixed diff --git a/Cargo.lock b/Cargo.lock index f5c8336..ba17388 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -785,10 +785,10 @@ dependencies = [ "email_address", "env_logger", "erased-serde", - "himalaya-lib", "indicatif", "log", "once_cell", + "pimalaya-email", "serde", "serde_json", "shellexpand", @@ -801,45 +801,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "himalaya-lib" -version = "0.6.0" -source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#7b8fb1d073b66d2f1d642df109c787ba3c31378f" -dependencies = [ - "ammonia", - "chrono", - "convert_case", - "dirs", - "html-escape", - "imap", - "imap-proto", - "lettre", - "log", - "mail-parser", - "maildir", - "mailparse", - "md5", - "mime-msg-builder", - "native-tls", - "notmuch", - "once_cell", - "ouroboros", - "proc-lock", - "rayon", - "regex", - "rfc2047-decoder", - "rusqlite", - "rustls", - "rustls-native-certs", - "shellexpand", - "thiserror", - "tree_magic", - "urlencoding", - "utf7-imap", - "uuid", - "webpki-roots", -] - [[package]] name = "hostname" version = "0.3.1" @@ -1225,7 +1186,8 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "mime-msg-builder" version = "0.1.0" -source = "git+https://git.sr.ht/~soywod/mime-msg-builder?branch=develop#1f61083ba7811bf261647056e63441d2f997113c" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3981dce6db3e7f9faa1124409a6b94436902ecb2670f374d361789d61eb34ac" dependencies = [ "ammonia", "chumsky 0.9.0", @@ -1544,6 +1506,44 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pimalaya-email" +version = "0.6.0" +dependencies = [ + "ammonia", + "chrono", + "convert_case", + "dirs", + "html-escape", + "imap", + "imap-proto", + "lettre", + "log", + "mail-parser", + "maildir", + "mailparse", + "md5", + "mime-msg-builder", + "native-tls", + "notmuch", + "once_cell", + "ouroboros", + "proc-lock", + "rayon", + "regex", + "rfc2047-decoder", + "rusqlite", + "rustls", + "rustls-native-certs", + "shellexpand", + "thiserror", + "tree_magic", + "urlencoding", + "utf7-imap", + "uuid", + "webpki-roots", +] + [[package]] name = "pin-project-lite" version = "0.2.9" diff --git a/Cargo.toml b/Cargo.toml index 9c64cee..21f5b04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "himalaya" -description = "Command-line interface for email management." +description = "CLI to manage your emails." version = "0.7.1" authors = ["soywod "] edition = "2021" license = "MIT" categories = ["command-line-interface", "command-line-utilities", "email"] keywords = ["cli", "mail", "email", "client", "imap"] -homepage = "https://github.com/soywod/himalaya" -documentation = "https://github.com/soywod/himalaya/wiki" +homepage = "https://pimalaya.org/himalaya/" +documentation = "https://pimalaya.org/himalaya/" repository = "https://github.com/soywod/himalaya" [package.metadata.deb] @@ -19,19 +19,19 @@ section = "mail" default = ["imap-backend", "smtp-sender", "native-tls"] # backends -imap-backend = ["himalaya-lib/imap-backend"] -notmuch-backend = ["himalaya-lib/notmuch-backend"] +imap-backend = ["pimalaya-email/imap-backend"] +notmuch-backend = ["pimalaya-email/notmuch-backend"] # senders -smtp-sender = ["himalaya-lib/smtp-sender"] +smtp-sender = ["pimalaya-email/smtp-sender"] # native tls -native-tls = ["himalaya-lib/native-tls"] -native-tls-vendored = ["himalaya-lib/native-tls-vendored"] +native-tls = ["pimalaya-email/native-tls"] +native-tls-vendored = ["pimalaya-email/native-tls-vendored"] # rustls -rustls-tls = ["himalaya-lib/rustls-tls"] -rustls-native-certs = ["himalaya-lib/rustls-native-certs"] +rustls-tls = ["pimalaya-email/rustls-tls"] +rustls-native-certs = ["pimalaya-email/rustls-native-certs"] [dev-dependencies] tempfile = "3.3" @@ -49,7 +49,8 @@ dialoguer = "0.10.2" email_address = "0.2.4" env_logger = "0.8" erased-serde = "0.3" -himalaya-lib = { git = "https://git.sr.ht/~soywod/himalaya-lib", branch = "develop" } +# pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya/email" } +pimalaya-email = { path = "/home/soywod/sourcehut/pimalaya/email" } indicatif = "0.17" log = "0.4" once_cell = "1.16.0" diff --git a/README.md b/README.md index a494021..15ff35c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # šŸ“« Himalaya [![GitHub release](https://img.shields.io/github/v/release/soywod/himalaya?color=success)](https://github.com/soywod/himalaya/releases/latest) [![Matrix](https://img.shields.io/matrix/pimalaya.himalaya:matrix.org?color=success&label=chat)](https://matrix.to/#/#pimalaya.himalaya:matrix.org) -Himalaya is a CLI based on the -[himalaya-lib](https://git.sr.ht/~soywod/himalaya-lib) that allows you -to manipulate your emails using commands in your console. +https://pimalaya.org/himalaya/ + +CLI to manage your emails, based on the +[pimalaya-email](https://sr.ht/~soywod/pimalaya/) library. ![image](https://user-images.githubusercontent.com/10437171/138774902-7b9de5a3-93eb-44b0-8cfb-6d2e11e3b1aa.png) @@ -25,19 +26,19 @@ production before the `v1.0.0`.* - JSON output - ā€¦ -[Folder listing]: https://pimalaya.org/himalaya/docs/cli/usage/folders/list.html -[Envelopes listing]: https://pimalaya.org/himalaya/docs/cli/usage/envelopes/list.html -[searching]: https://pimalaya.org/himalaya/docs/cli/usage/envelopes/search.html -[sorting]: https://pimalaya.org/himalaya/docs/cli/usage/envelopes/sort.html -[Email composition]: https://pimalaya.org/himalaya/docs/cli/usage/emails/write.html -[copy]: https://pimalaya.org/himalaya/docs/cli/usage/emails/copy.html -[move]: https://pimalaya.org/himalaya/docs/cli/usage/emails/move.html -[delete]: https://pimalaya.org/himalaya/docs/cli/usage/emails/delete.html -[Multi-accounting]: https://pimalaya.org/himalaya/docs/cli/configuration.html -[Account listing]: https://pimalaya.org/himalaya/docs/cli/usage/accounts/list.html -[Account synchronization]: https://pimalaya.org/himalaya/docs/cli/usage/accounts/synchronize.html -[real-time notifications]: https://pimalaya.org/himalaya/docs/cli/usage/notifications.html -[Completions]: https://pimalaya.org/himalaya/docs/cli/tips/completion.html +[Folder listing]: https://pimalaya.org/himalaya/cli/usage/folders/list.html +[Envelopes listing]: https://pimalaya.org/himalaya/cli/usage/envelopes/list.html +[searching]: https://pimalaya.org/himalaya/cli/usage/envelopes/search.html +[sorting]: https://pimalaya.org/himalaya/cli/usage/envelopes/sort.html +[Email composition]: https://pimalaya.org/himalaya/cli/usage/emails/write.html +[copy]: https://pimalaya.org/himalaya/cli/usage/emails/copy.html +[move]: https://pimalaya.org/himalaya/cli/usage/emails/move.html +[delete]: https://pimalaya.org/himalaya/cli/usage/emails/delete.html +[Multi-accounting]: https://pimalaya.org/himalaya/cli/configuration.html +[Account listing]: https://pimalaya.org/himalaya/cli/usage/accounts/list.html +[Account synchronization]: https://pimalaya.org/himalaya/cli/usage/accounts/synchronize.html +[real-time notifications]: https://pimalaya.org/himalaya/cli/usage/notifications.html +[Completions]: https://pimalaya.org/himalaya/cli/tips/completion.html ## Installation @@ -71,7 +72,7 @@ $ nix-env -i himalaya ``` *See the -[documentation](https://pimalaya.org/himalaya/docs/cli/installation.html) +[documentation](https://pimalaya.org/himalaya/cli/installation.html) for other installation methods.* @@ -81,11 +82,12 @@ for other installation methods.* ## Configuration Please read the -[documentation](https://pimalaya.org/himalaya/docs/cli/configuration.html). +[documentation](https://pimalaya.org/himalaya/cli/configuration.html). ## Contributing -If you find a **bug**, please send an email at +If you find a **bug** that [does not exist +yet](https://todo.sr.ht/~soywod/pimalaya), please send an email at [~soywod/pimalaya@todo.sr.ht](mailto:~soywod/pimalaya@todo.sr.ht). If you have a **question**, please send an email at diff --git a/src/config/config.rs b/src/config/config.rs index ccc23cf..caeded6 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -5,8 +5,8 @@ use anyhow::{anyhow, Context, Result}; use dirs::{config_dir, home_dir}; -use himalaya_lib::{AccountConfig, BackendConfig, EmailHooks, EmailTextPlainFormat}; use log::{debug, trace}; +use pimalaya_email::{AccountConfig, BackendConfig, EmailHooks, EmailTextPlainFormat}; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs, path::PathBuf}; use toml; @@ -119,12 +119,12 @@ impl DeserializedConfig { #[cfg(test)] mod tests { - use himalaya_lib::{EmailSender, MaildirConfig, SendmailConfig, SmtpConfig}; + use pimalaya_email::{EmailSender, MaildirConfig, SendmailConfig, SmtpConfig}; #[cfg(feature = "imap-backend")] - use himalaya_lib::ImapConfig; + use pimalaya_email::ImapConfig; #[cfg(feature = "notmuch-backend")] - use himalaya_lib::NotmuchConfig; + use pimalaya_email::NotmuchConfig; use std::io::Write; use tempfile::NamedTempFile; diff --git a/src/config/prelude.rs b/src/config/prelude.rs index 82f5528..d121f28 100644 --- a/src/config/prelude.rs +++ b/src/config/prelude.rs @@ -1,4 +1,4 @@ -use himalaya_lib::{ +use pimalaya_email::{ folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat, MaildirConfig, SendmailConfig, SmtpConfig, }; @@ -6,10 +6,10 @@ use serde::{Deserialize, Serialize}; use std::{collections::HashSet, path::PathBuf}; #[cfg(feature = "imap-backend")] -use himalaya_lib::ImapConfig; +use pimalaya_email::ImapConfig; #[cfg(feature = "notmuch-backend")] -use himalaya_lib::NotmuchConfig; +use pimalaya_email::NotmuchConfig; #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "SmtpConfig")] diff --git a/src/config/wizard/imap.rs b/src/config/wizard/imap.rs index 74d93eb..33f4b8e 100644 --- a/src/config/wizard/imap.rs +++ b/src/config/wizard/imap.rs @@ -4,7 +4,7 @@ use crate::account::{ }; use anyhow::Result; use dialoguer::{Input, Select}; -use himalaya_lib::ImapConfig; +use pimalaya_email::ImapConfig; #[cfg(feature = "imap-backend")] pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result { diff --git a/src/config/wizard/maildir.rs b/src/config/wizard/maildir.rs index 2670301..037deb2 100644 --- a/src/config/wizard/maildir.rs +++ b/src/config/wizard/maildir.rs @@ -5,7 +5,7 @@ use crate::account::{ use anyhow::Result; use dialoguer::Input; use dirs::home_dir; -use himalaya_lib::MaildirConfig; +use pimalaya_email::MaildirConfig; pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result { let input = if let Some(home) = home_dir() { diff --git a/src/config/wizard/notmuch.rs b/src/config/wizard/notmuch.rs index 15a78b1..df9cc6f 100644 --- a/src/config/wizard/notmuch.rs +++ b/src/config/wizard/notmuch.rs @@ -4,7 +4,7 @@ use crate::account::{ }; use anyhow::Result; use dialoguer::Input; -use himalaya_lib::{NotmuchBackend, NotmuchConfig}; +use pimalaya_email::{NotmuchBackend, NotmuchConfig}; pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result { let db_path = match NotmuchBackend::get_default_db_path() { diff --git a/src/config/wizard/sendmail.rs b/src/config/wizard/sendmail.rs index 82ae1a6..734fe69 100644 --- a/src/config/wizard/sendmail.rs +++ b/src/config/wizard/sendmail.rs @@ -1,7 +1,7 @@ use super::THEME; use anyhow::Result; use dialoguer::Input; -use himalaya_lib::{EmailSender, SendmailConfig}; +use pimalaya_email::{EmailSender, SendmailConfig}; pub(crate) fn configure() -> Result { Ok(EmailSender::Sendmail(SendmailConfig { diff --git a/src/config/wizard/smtp.rs b/src/config/wizard/smtp.rs index 3d0359d..197973f 100644 --- a/src/config/wizard/smtp.rs +++ b/src/config/wizard/smtp.rs @@ -2,7 +2,7 @@ use super::{SECURITY_PROTOCOLS, THEME}; use crate::account::DeserializedBaseAccountConfig; use anyhow::Result; use dialoguer::{Input, Select}; -use himalaya_lib::{EmailSender, SmtpConfig}; +use pimalaya_email::{EmailSender, SmtpConfig}; pub(crate) fn configure(base: &DeserializedBaseAccountConfig) -> Result { let mut smtp_config = SmtpConfig { diff --git a/src/domain/account/args.rs b/src/domain/account/args.rs index 7449f74..02233da 100644 --- a/src/domain/account/args.rs +++ b/src/domain/account/args.rs @@ -2,8 +2,8 @@ use anyhow::Result; use clap::{Arg, ArgAction, ArgMatches, Command}; -use himalaya_lib::folder::sync::Strategy as SyncFoldersStrategy; use log::info; +use pimalaya_email::folder::sync::Strategy as SyncFoldersStrategy; use std::collections::HashSet; use crate::{folder, ui::table}; diff --git a/src/domain/account/config.rs b/src/domain/account/config.rs index 6086dbb..4fd3d01 100644 --- a/src/domain/account/config.rs +++ b/src/domain/account/config.rs @@ -3,7 +3,7 @@ //! This module contains the raw deserialized representation of an //! account in the accounts section of the user configuration file. -use himalaya_lib::{ +use pimalaya_email::{ folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, BackendConfig, EmailHooks, EmailSender, EmailTextPlainFormat, MaildirConfig, }; @@ -11,10 +11,10 @@ use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path::PathBuf}; #[cfg(feature = "imap-backend")] -use himalaya_lib::ImapConfig; +use pimalaya_email::ImapConfig; #[cfg(feature = "notmuch-backend")] -use himalaya_lib::NotmuchConfig; +use pimalaya_email::NotmuchConfig; use crate::config::{prelude::*, DeserializedConfig}; diff --git a/src/domain/account/handlers.rs b/src/domain/account/handlers.rs index 442ad04..a0e4e33 100644 --- a/src/domain/account/handlers.rs +++ b/src/domain/account/handlers.rs @@ -3,12 +3,12 @@ //! This module gathers all account actions triggered by the CLI. use anyhow::Result; -use himalaya_lib::{ +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use log::{info, trace}; +use pimalaya_email::{ folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, Backend, BackendSyncBuilder, BackendSyncProgressEvent, }; -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use log::{info, trace}; use crate::{ config::DeserializedConfig, @@ -226,7 +226,7 @@ pub fn sync( #[cfg(test)] mod tests { - use himalaya_lib::{AccountConfig, ImapConfig}; + use pimalaya_email::{AccountConfig, ImapConfig}; use std::{collections::HashMap, fmt::Debug, io}; use termcolor::ColorSpec; diff --git a/src/domain/email/handlers.rs b/src/domain/email/handlers.rs index 20b1d2c..6ddca41 100644 --- a/src/domain/email/handlers.rs +++ b/src/domain/email/handlers.rs @@ -1,9 +1,9 @@ use anyhow::{anyhow, Context, Result}; use atty::Stream; -use himalaya_lib::{ +use log::{debug, trace}; +use pimalaya_email::{ AccountConfig, Backend, Email, Flag, Flags, Sender, ShowTextPartsStrategy, Tpl, TplBuilder, }; -use log::{debug, trace}; use std::{ fs, io::{self, BufRead}, diff --git a/src/domain/envelope/envelope.rs b/src/domain/envelope/envelope.rs index 5c24133..d58c499 100644 --- a/src/domain/envelope/envelope.rs +++ b/src/domain/envelope/envelope.rs @@ -26,8 +26,8 @@ pub struct Envelope { pub date: DateTime, } -impl From<&himalaya_lib::Envelope> for Envelope { - fn from(envelope: &himalaya_lib::Envelope) -> Self { +impl From<&pimalaya_email::Envelope> for Envelope { + fn from(envelope: &pimalaya_email::Envelope) -> Self { Envelope { id: envelope.id.clone(), flags: envelope.flags.clone().into(), diff --git a/src/domain/envelope/envelopes.rs b/src/domain/envelope/envelopes.rs index 1842e8b..3efe2d3 100644 --- a/src/domain/envelope/envelopes.rs +++ b/src/domain/envelope/envelopes.rs @@ -21,8 +21,8 @@ impl ops::Deref for Envelopes { } } -impl From for Envelopes { - fn from(envelopes: himalaya_lib::Envelopes) -> Self { +impl From for Envelopes { + fn from(envelopes: pimalaya_email::Envelopes) -> Self { Envelopes(envelopes.iter().map(Envelope::from).collect()) } } diff --git a/src/domain/flag/args.rs b/src/domain/flag/args.rs index 5a660a0..32fe191 100644 --- a/src/domain/flag/args.rs +++ b/src/domain/flag/args.rs @@ -5,8 +5,8 @@ use anyhow::Result; use clap::{Arg, ArgMatches, Command}; -use himalaya_lib::{Flag, Flags}; use log::{debug, info}; +use pimalaya_email::{Flag, Flags}; use crate::email; diff --git a/src/domain/flag/flag.rs b/src/domain/flag/flag.rs index d9f2832..daea47c 100644 --- a/src/domain/flag/flag.rs +++ b/src/domain/flag/flag.rs @@ -11,15 +11,15 @@ pub enum Flag { Custom(String), } -impl From<&himalaya_lib::Flag> for Flag { - fn from(flag: &himalaya_lib::Flag) -> Self { +impl From<&pimalaya_email::Flag> for Flag { + fn from(flag: &pimalaya_email::Flag) -> Self { match flag { - himalaya_lib::Flag::Seen => Flag::Seen, - himalaya_lib::Flag::Answered => Flag::Answered, - himalaya_lib::Flag::Flagged => Flag::Flagged, - himalaya_lib::Flag::Deleted => Flag::Deleted, - himalaya_lib::Flag::Draft => Flag::Draft, - himalaya_lib::Flag::Custom(flag) => Flag::Custom(flag.clone()), + pimalaya_email::Flag::Seen => Flag::Seen, + pimalaya_email::Flag::Answered => Flag::Answered, + pimalaya_email::Flag::Flagged => Flag::Flagged, + pimalaya_email::Flag::Deleted => Flag::Deleted, + pimalaya_email::Flag::Draft => Flag::Draft, + pimalaya_email::Flag::Custom(flag) => Flag::Custom(flag.clone()), } } } diff --git a/src/domain/flag/flags.rs b/src/domain/flag/flags.rs index b413526..534cb97 100644 --- a/src/domain/flag/flags.rs +++ b/src/domain/flag/flags.rs @@ -14,8 +14,8 @@ impl ops::Deref for Flags { } } -impl From for Flags { - fn from(flags: himalaya_lib::Flags) -> Self { +impl From for Flags { + fn from(flags: pimalaya_email::Flags) -> Self { Flags(flags.iter().map(Flag::from).collect()) } } diff --git a/src/domain/flag/handlers.rs b/src/domain/flag/handlers.rs index 1f3eb66..0e184f7 100644 --- a/src/domain/flag/handlers.rs +++ b/src/domain/flag/handlers.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use himalaya_lib::{Backend, Flags}; +use pimalaya_email::{Backend, Flags}; use crate::printer::Printer; diff --git a/src/domain/folder/folder.rs b/src/domain/folder/folder.rs index 8e201d2..0aebace 100644 --- a/src/domain/folder/folder.rs +++ b/src/domain/folder/folder.rs @@ -9,8 +9,8 @@ pub struct Folder { pub desc: String, } -impl From<&himalaya_lib::Folder> for Folder { - fn from(folder: &himalaya_lib::Folder) -> Self { +impl From<&pimalaya_email::Folder> for Folder { + fn from(folder: &pimalaya_email::Folder) -> Self { Folder { delim: folder.delim.clone(), name: folder.name.clone(), diff --git a/src/domain/folder/folders.rs b/src/domain/folder/folders.rs index 93426d8..d3335ae 100644 --- a/src/domain/folder/folders.rs +++ b/src/domain/folder/folders.rs @@ -20,8 +20,8 @@ impl ops::Deref for Folders { } } -impl From for Folders { - fn from(folders: himalaya_lib::Folders) -> Self { +impl From for Folders { + fn from(folders: pimalaya_email::Folders) -> Self { Folders(folders.iter().map(Folder::from).collect()) } } diff --git a/src/domain/folder/handlers.rs b/src/domain/folder/handlers.rs index dc7b7f4..2e2a384 100644 --- a/src/domain/folder/handlers.rs +++ b/src/domain/folder/handlers.rs @@ -4,7 +4,7 @@ use anyhow::Result; use dialoguer::Confirm; -use himalaya_lib::{AccountConfig, Backend}; +use pimalaya_email::{AccountConfig, Backend}; use std::process; use crate::{ @@ -67,7 +67,7 @@ pub fn delete( #[cfg(test)] mod tests { - use himalaya_lib::{ + use pimalaya_email::{ backend, AccountConfig, Backend, Emails, Envelope, Envelopes, Flags, Folder, Folders, }; use std::{any::Any, fmt::Debug, io}; diff --git a/src/domain/imap/handlers.rs b/src/domain/imap/handlers.rs index 3302700..d664d30 100644 --- a/src/domain/imap/handlers.rs +++ b/src/domain/imap/handlers.rs @@ -3,7 +3,7 @@ //! This module gathers all IMAP handlers triggered by the CLI. use anyhow::{Context, Result}; -use himalaya_lib::ImapBackend; +use pimalaya_email::ImapBackend; pub fn notify(imap: &ImapBackend, folder: &str, keepalive: u64) -> Result<()> { imap.notify(keepalive, folder).context("cannot imap notify") diff --git a/src/domain/tpl/handlers.rs b/src/domain/tpl/handlers.rs index 51920e2..9f09b3b 100644 --- a/src/domain/tpl/handlers.rs +++ b/src/domain/tpl/handlers.rs @@ -1,6 +1,6 @@ use anyhow::{anyhow, Result}; use atty::Stream; -use himalaya_lib::{AccountConfig, Backend, CompilerBuilder, Email, Flags, Sender, Tpl}; +use pimalaya_email::{AccountConfig, Backend, CompilerBuilder, Email, Flags, Sender, Tpl}; use std::io::{stdin, BufRead}; use crate::printer::Printer; diff --git a/src/main.rs b/src/main.rs index bfd2ac4..37669fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use himalaya::{ printer::StdoutPrinter, tpl, }; -use himalaya_lib::{ +use pimalaya_email::{ BackendBuilder, BackendConfig, ImapBackend, SenderBuilder, DEFAULT_INBOX_FOLDER, }; diff --git a/src/printer/print.rs b/src/printer/print.rs index 7f03a5f..680fb11 100644 --- a/src/printer/print.rs +++ b/src/printer/print.rs @@ -1,5 +1,5 @@ use anyhow::{Context, Result}; -use himalaya_lib::Tpl; +use pimalaya_email::Tpl; use crate::printer::WriteColor; diff --git a/src/printer/print_table.rs b/src/printer/print_table.rs index bf6d75f..a2f847a 100644 --- a/src/printer/print_table.rs +++ b/src/printer/print_table.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use himalaya_lib::EmailTextPlainFormat; +use pimalaya_email::EmailTextPlainFormat; use std::io; use termcolor::{self, StandardStream}; diff --git a/src/ui/editor.rs b/src/ui/editor.rs index 3ef83d5..87ca7b1 100644 --- a/src/ui/editor.rs +++ b/src/ui/editor.rs @@ -1,9 +1,9 @@ use anyhow::{Context, Result}; -use himalaya_lib::{ +use log::debug; +use pimalaya_email::{ email::{local_draft_path, remove_local_draft}, AccountConfig, Backend, CompilerBuilder, Flag, Flags, Sender, Tpl, }; -use log::debug; use std::{env, fs, process::Command}; use crate::{ diff --git a/src/ui/table/table.rs b/src/ui/table/table.rs index de2dbde..4c43540 100644 --- a/src/ui/table/table.rs +++ b/src/ui/table/table.rs @@ -5,8 +5,8 @@ //! [builder design pattern]: https://refactoring.guru/design-patterns/builder use anyhow::{Context, Result}; -use himalaya_lib::EmailTextPlainFormat; use log::trace; +use pimalaya_email::EmailTextPlainFormat; use termcolor::{Color, ColorSpec}; use terminal_size; use unicode_width::UnicodeWidthStr; From 9cf5003697d0a934302b1e12175451640ce2aebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Tue, 25 Apr 2023 09:39:49 +0200 Subject: [PATCH 18/19] update changelog --- CHANGELOG.md | 6 ++++++ Cargo.lock | 2 ++ Cargo.toml | 8 +++----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d667a1e..1349cb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 synchronization. They can be repeated `-x folder1 folder2` or `-x folder1 -F folder2`. +- Added cargo features `native-tls` (default), `rustls-tls` and + `rustls-native-certs`. + ### Changed - Made global options truly global, which means they can be used @@ -42,6 +45,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Replaced reply all `-a` argument with `-A` because it conflicted with the global option `-a|--account`. - Replaced `himalaya-lib` by `pimalaya-email`. +- Renamed feature `vendored` to `native-tls-vendored`. +- Removed the `develop` branch, all the development is now done on the + `master` branch. ### Fixed diff --git a/Cargo.lock b/Cargo.lock index ba17388..bc7deeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1509,6 +1509,8 @@ dependencies = [ [[package]] name = "pimalaya-email" version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15171f3839bb7b7938f78b0c43902247d7f1e80befccd63f6cab93ac55613405" dependencies = [ "ammonia", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 21f5b04..edccaae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,8 @@ homepage = "https://pimalaya.org/himalaya/" documentation = "https://pimalaya.org/himalaya/" repository = "https://github.com/soywod/himalaya" -[package.metadata.deb] -priority = "optional" -section = "mail" +[package.metadata.docs.rs] +all-features = true [features] default = ["imap-backend", "smtp-sender", "native-tls"] @@ -49,8 +48,7 @@ dialoguer = "0.10.2" email_address = "0.2.4" env_logger = "0.8" erased-serde = "0.3" -# pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya/email" } -pimalaya-email = { path = "/home/soywod/sourcehut/pimalaya/email" } +pimalaya-email = "0.6.0" indicatif = "0.17" log = "0.4" once_cell = "1.16.0" From 84003f951a19eb761dcb869dadfb5bfa67b81619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Mon, 1 May 2023 00:19:59 +0200 Subject: [PATCH 19/19] improve cross compilation, prepare v0.7.2 --- .github/workflows/deployment.yml | 121 ---------------------- .github/workflows/nix.yml | 38 ------- .github/workflows/release.yml | 150 +++++++++++++++++++++++++++ .github/workflows/tests.yml | 36 ++----- CHANGELOG.md | 5 +- Cargo.lock | 34 +++--- Cargo.toml | 22 ++-- flake.lock | 152 +++++++++++++-------------- flake.nix | 171 ++++++++++++++++++++++--------- rust-toolchain.toml | 9 ++ 10 files changed, 404 insertions(+), 334 deletions(-) delete mode 100644 .github/workflows/deployment.yml delete mode 100644 .github/workflows/nix.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml deleted file mode 100644 index bb3461c..0000000 --- a/.github/workflows/deployment.yml +++ /dev/null @@ -1,121 +0,0 @@ -name: deployment - -on: - push: - tags: - - v* - -jobs: - create_release: - runs-on: ubuntu-latest - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} - steps: - - name: Create release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: ${{ github.ref }} - draft: false - prerelease: false - deploy_linux_macos_windows_github: - runs-on: ${{ matrix.os }} - needs: create_release - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - os_name: linux - - os: macos-latest - os_name: macos - - os: windows-latest - os_name: windows - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Install rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - name: Check project - uses: actions-rs/cargo@v1 - with: - command: check - - name: Builds release - uses: actions-rs/cargo@v1 - with: - command: build - args: --release - - name: Compress executable (unix) - if: matrix.os_name == 'linux' || matrix.os_name == 'macos' - run: | - mkdir -p target/release/{man,completions} - target/release/himalaya man target/release/man - target/release/himalaya completion bash > target/release/completions/himalaya.bash - target/release/himalaya completion elvish > target/release/completions/himalaya.elvish - target/release/himalaya completion fish > target/release/completions/himalaya.fish - target/release/himalaya completion powershell > target/release/completions/himalaya.powershell - target/release/himalaya completion zsh > target/release/completions/himalaya.zsh - tar czf himalaya.tar.gz -C target/release himalaya man completions - - name: Compress executable (windows) - if: matrix.os_name == 'windows' - run: | - mkdir -p target/release/{man,completions} - target/release/himalaya.exe man target/release/man - target/release/himalaya.exe completion bash > target/release/completions/himalaya.bash - target/release/himalaya.exe completion elvish > target/release/completions/himalaya.elvish - target/release/himalaya.exe completion fish > target/release/completions/himalaya.fish - target/release/himalaya.exe completion powershell > target/release/completions/himalaya.powershell - target/release/himalaya.exe completion zsh > target/release/completions/himalaya.zsh - tar czf himalaya.tar.gz -C target/release himalaya.exe man completions - - name: Upload release asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create_release.outputs.upload_url }} - asset_path: himalaya.tar.gz - asset_name: himalaya-${{ matrix.os_name }}.tar.gz - asset_content_type: application/gzip - deploy_musl_github: - runs-on: ubuntu-latest - needs: create_release - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Build release - run: | - docker run -v "${PWD}:/volume" --rm -t clux/muslrust:stable cargo build --release - - name: Compress executable - run: tar czf himalaya.tar.gz -C target/x86_64-unknown-linux-musl/release himalaya - - name: Upload release asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create_release.outputs.upload_url }} - asset_path: himalaya.tar.gz - asset_name: himalaya-musl.tar.gz - asset_content_type: application/gzip - deploy_crates: - runs-on: ubuntu-latest - needs: create_release - environment: deployment - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Install rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: katyo/publish-crates@v1 - with: - registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml deleted file mode 100644 index 46069ef..0000000 --- a/.github/workflows/nix.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: nix - -on: - pull_request: - push: - branches: - - master - -jobs: - nix-build: - runs-on: ubuntu-latest - steps: - - name: Checkouts code - uses: actions/checkout@v3 - - - name: Caches Nix store - uses: actions/cache@v3 - id: nix-cache - with: - path: /tmp/nix-cache - key: nix-${{ hashFiles('**/flake.*') }} - - - name: Installs Nix - uses: cachix/install-nix-action@v18 - with: - extra_nix_config: | - experimental-features = nix-command flakes - - - name: Imports Nix store cache - if: ${{ steps.nix-cache.outputs.cache-hit == 'true' }} - run: nix-store --import < /tmp/nix-cache - - - name: Builds the project - run: nix build - - - name: Exports Nix store cache - if: ${{ steps.nix-cache.outputs.cache-hit != 'true' }} - run: nix-store --export $(find /nix/store -maxdepth 1 -name '*-*') > /tmp/nix-cache diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3004c9c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,150 @@ +name: release + +on: + push: + tags: + - v* + +jobs: + create_release: + runs-on: ubuntu-latest + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + steps: + - name: Create release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + draft: false + prerelease: false + + deploy_github: + runs-on: ${{ matrix.os }} + needs: create_release + strategy: + fail-fast: false + matrix: + include: + - target: linux + os: ubuntu-latest + - target: macos + os: macos-latest + - target: musl + os: ubuntu-latest + # TODO: put back when nix package .#windows is fixed + # - target: windows + # os: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Install Nix + uses: cachix/install-nix-action@v20 + with: + nix_path: nixpkgs=channel:nixos-unstable + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v12 + with: + name: soywod + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - name: Build release + run: nix build .#${{ matrix.target }} + - name: Compress executable + run: | + mkdir -p {man,completions} + cp result/bin/himalaya* . + nix run .#${{ matrix.target }} man ./man + nix run .#${{ matrix.target }} completion bash > ./completions/himalaya.bash + nix run .#${{ matrix.target }} completion elvish > ./completions/himalaya.elvish + nix run .#${{ matrix.target }} completion fish > ./completions/himalaya.fish + nix run .#${{ matrix.target }} completion powershell > ./completions/himalaya.powershell + nix run .#${{ matrix.target }} completion zsh > ./completions/himalaya.zsh + tar -czf himalaya.tar.gz himalaya* man completions + zip -r himalaya.zip himalaya* man completions + - name: Upload tar.gz release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: himalaya.tar.gz + asset_name: himalaya-${{ matrix.target }}.tar.gz + asset_content_type: application/gzip + - name: Upload zip release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: himalaya.zip + asset_name: himalaya-${{ matrix.target }}.zip + asset_content_type: application/zip + + # TODO: remove me when nix package .#windows is fixed + deploy_windows_github: + runs-on: windows-latest + needs: create_release + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Install rust + uses: actions-rs/toolchain@v1 + with: + command: check + - name: Builds release + uses: actions-rs/cargo@v1 + with: + command: build + args: --release + - name: Compress executable + run: | + mkdir man + mkdir completions + copy target/release/himalaya.exe . + ./himalaya.exe man ./man + ./himalaya.exe completion bash > ./completions/himalaya.bash + ./himalaya.exe completion elvish > ./completions/himalaya.elvish + ./himalaya.exe completion fish > ./completions/himalaya.fish + ./himalaya.exe completion powershell > ./completions/himalaya.powershell + ./himalaya.exe completion zsh > ./completions/himalaya.zsh + tar -czf himalaya.tar.gz himalaya.exe man completions + zip -r himalaya.zip himalaya.exe man completions + - name: Upload tar.gz release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: himalaya.tar.gz + asset_name: himalaya-windows.tar.gz + asset_content_type: application/gzip + - name: Upload zip release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + asset_path: himalaya.zip + asset_name: himalaya-windows.zip + asset_content_type: application/zip + + deploy_crates: + runs-on: ubuntu-latest + needs: create_release + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Install Nix + uses: cachix/install-nix-action@v20 + with: + nix_path: nixpkgs=channel:nixos-unstable + extra_nix_config: | + experimental-features = nix-command flakes + - name: Publish library to crates.io + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: nix develop -c cargo publish --no-verify --token ${CARGO_REGISTRY_TOKEN} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f315921..d346b05 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,36 +3,22 @@ name: tests on: pull_request: push: - branches: - - master jobs: tests: runs-on: ubuntu-latest steps: - - name: Install libnotmuch - run: sudo apt-get install -y libnotmuch-dev - name: Checkout code - uses: actions/checkout@v2 - - name: Start GreenMail testing server - run: | - docker run \ - --rm \ - -d \ - -e GREENMAIL_OPTS='-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose' \ - -p 3025:3025 \ - -p 3110:3110 \ - -p 3143:3143 \ - -p 3465:3465 \ - -p 3993:3993 \ - -p 3995:3995 \ - greenmail/standalone:1.6.11 - - name: Install rust - uses: actions-rs/toolchain@v1 + uses: actions/checkout@v2 + - name: Install Nix + uses: cachix/install-nix-action@v20 with: - toolchain: stable - - name: Run tests - uses: actions-rs/cargo@v1 + nix_path: nixpkgs=channel:nixos-unstable + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v12 with: - command: test - args: --all-features + name: soywod + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - name: Test + run: nix run .#test diff --git a/CHANGELOG.md b/CHANGELOG.md index 1349cb5..48147cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.7.2] - 2023-05-01 + ### Added - Added `create` and `delete` folder commands [sourcehut#54]. @@ -546,7 +548,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Password from command [#22] - Set up README [#20] -[Unreleased]: https://github.com/soywod/himalaya/compare/v0.7.1...develop +[Unreleased]: https://github.com/soywod/himalaya/compare/v0.7.2...develop +[0.7.2]: https://github.com/soywod/himalaya/compare/v0.7.1...v0.7.2 [0.7.1]: https://github.com/soywod/himalaya/compare/v0.7.0...v0.7.1 [0.7.0]: https://github.com/soywod/himalaya/compare/v0.6.1...v0.7.0 [0.6.1]: https://github.com/soywod/himalaya/compare/v0.6.0...v0.6.1 diff --git a/Cargo.lock b/Cargo.lock index bc7deeb..4b40a4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" + [[package]] name = "bufstream" version = "0.1.4" @@ -186,7 +192,7 @@ version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_lex", "is-terminal", "strsim 0.10.0", @@ -227,7 +233,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -771,7 +777,7 @@ dependencies = [ [[package]] name = "himalaya" -version = "0.7.1" +version = "0.7.2" dependencies = [ "anyhow", "atty", @@ -1023,9 +1029,9 @@ checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libsqlite3-sys" -version = "0.25.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" dependencies = [ "cc", "pkg-config", @@ -1327,7 +1333,7 @@ version = "0.10.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "foreign-types", "libc", @@ -1508,9 +1514,9 @@ dependencies = [ [[package]] name = "pimalaya-email" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15171f3839bb7b7938f78b0c43902247d7f1e80befccd63f6cab93ac55613405" +checksum = "bab7e9b0747644aecff24024c88348146bd74bba78fa5ecca10e7e5938d6873a" dependencies = [ "ammonia", "chrono", @@ -1741,7 +1747,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1818,11 +1824,11 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rusqlite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags", + "bitflags 2.2.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -1836,7 +1842,7 @@ version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -1933,7 +1939,7 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", diff --git a/Cargo.toml b/Cargo.toml index edccaae..6f5197e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "himalaya" description = "CLI to manage your emails." -version = "0.7.1" +version = "0.7.2" authors = ["soywod "] edition = "2021" license = "MIT" @@ -15,7 +15,15 @@ repository = "https://github.com/soywod/himalaya" all-features = true [features] -default = ["imap-backend", "smtp-sender", "native-tls"] +default = ["rustls-tls", "rustls-native-certs", "imap-backend", "smtp-sender"] + +# rustls +rustls-tls = ["pimalaya-email/rustls-tls"] +rustls-native-certs = ["pimalaya-email/rustls-native-certs"] + +# native tls +native-tls = ["pimalaya-email/native-tls"] +native-tls-vendored = ["pimalaya-email/native-tls-vendored"] # backends imap-backend = ["pimalaya-email/imap-backend"] @@ -24,14 +32,6 @@ notmuch-backend = ["pimalaya-email/notmuch-backend"] # senders smtp-sender = ["pimalaya-email/smtp-sender"] -# native tls -native-tls = ["pimalaya-email/native-tls"] -native-tls-vendored = ["pimalaya-email/native-tls-vendored"] - -# rustls -rustls-tls = ["pimalaya-email/rustls-tls"] -rustls-native-certs = ["pimalaya-email/rustls-native-certs"] - [dev-dependencies] tempfile = "3.3" @@ -48,7 +48,7 @@ dialoguer = "0.10.2" email_address = "0.2.4" env_logger = "0.8" erased-serde = "0.3" -pimalaya-email = "0.6.0" +pimalaya-email = "0.7.1" indicatif = "0.17" log = "0.4" once_cell = "1.16.0" diff --git a/flake.lock b/flake.lock index 95c6151..a344611 100644 --- a/flake.lock +++ b/flake.lock @@ -1,28 +1,36 @@ { "nodes": { - "flake-compat": { - "flake": false, + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "lastModified": 1682835640, + "narHash": "sha256-rAYEOd4nZFLjDlrF9KNlcopPKNVtr1svSXcEValVRMY=", + "owner": "nix-community", + "repo": "fenix", + "rev": "006b429d3c493f4c5b1743a94f71ad961c7693ab", "type": "github" }, "original": { - "owner": "edolstra", - "repo": "flake-compat", + "owner": "nix-community", + "repo": "fenix", "type": "github" } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -31,16 +39,38 @@ "type": "github" } }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "naersk": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { - "lastModified": 1671096816, - "narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=", + "lastModified": 1679567394, + "narHash": "sha256-ZvLuzPeARDLiQUt6zSZFGOs+HZmE+3g4QURc8mkBsfM=", "owner": "nix-community", "repo": "naersk", - "rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114", + "rev": "88cd22380154a2c36799fe8098888f0f59861a15", "type": "github" }, "original": { @@ -51,88 +81,58 @@ }, "nixpkgs": { "locked": { - "lastModified": 1675698036, - "narHash": "sha256-BgsQkQewdlQi8gapJN4phpxkI/FCE/2sORBaFcYbp/A=", - "owner": "NixOS", + "lastModified": 1682669017, + "narHash": "sha256-Vi+p4y3wnl0/4gcwTdmCO398kKlDaUrNROtf3GOD2NY=", + "owner": "nixos", "repo": "nixpkgs", - "rev": "1046c7b92e908a1202c0f1ba3fc21d19e1cf1b62", + "rev": "7449971a3ecf857b4a554cf79b1d9dcc1a4647d8", "type": "github" }, "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1664356419, - "narHash": "sha256-PD0hM9YWp2lepAJk7edh8g1VtzJip5rals1fpoQUlY0=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "46e8398474ac3b1b7bb198bf9097fc213bbf59b1", - "type": "github" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1665296151, - "narHash": "sha256-uOB0oxqxN9K7XGF1hcnY+PQnlQJ+3bP2vCn/+Ru/bbc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "14ccaaedd95a488dd7ae142757884d8e125b3363", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", + "owner": "nixos", + "ref": "nixos-22.11", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { - "flake-compat": "flake-compat", - "naersk": "naersk", - "nixpkgs": "nixpkgs_2", - "rust-overlay": "rust-overlay", - "utils": "utils" - } - }, - "rust-overlay": { - "inputs": { + "fenix": "fenix", "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs_3" - }, + "gitignore": "gitignore", + "naersk": "naersk", + "nixpkgs": "nixpkgs" + } + }, + "rust-analyzer-src": { + "flake": false, "locked": { - "lastModified": 1675823425, - "narHash": "sha256-o/uLXQdq3OrRAv4BZVVY0VmhMmQBLWw6Y4o+p6ZiaR4=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "02e1abbdcbc2d516193ff8a7add71f44cd976ba0", + "lastModified": 1682792082, + "narHash": "sha256-1nuP2rqipsdB8IJ3N5ws3FQm4dX3mKIueIrCUSu1bWw=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "7bcb4c2ef23e151a639ff918fbb8ab9d521eabb9", "type": "github" }, "original": { - "owner": "oxalica", - "repo": "rust-overlay", + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", "type": "github" } }, - "utils": { + "systems": { "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { - "owner": "numtide", - "repo": "flake-utils", + "owner": "nix-systems", + "repo": "default", "type": "github" } } diff --git a/flake.nix b/flake.nix index b8baf74..34bc322 100644 --- a/flake.nix +++ b/flake.nix @@ -1,65 +1,140 @@ { - description = "Command-line interface for email management."; + description = "CLI to manage your emails."; inputs = { - utils.url = "github:numtide/flake-utils"; - rust-overlay.url = "github:oxalica/rust-overlay"; - naersk.url = "github:nix-community/naersk"; - flake-compat = { - url = "github:edolstra/flake-compat"; - flake = false; + nixpkgs.url = "github:nixos/nixpkgs/nixos-22.11"; + flake-utils.url = "github:numtide/flake-utils"; + gitignore = { + url = "github:hercules-ci/gitignore.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + naersk = { + url = "github:nix-community/naersk"; + inputs.nixpkgs.follows = "nixpkgs"; }; }; - outputs = { self, nixpkgs, utils, rust-overlay, naersk, ... }: - utils.lib.eachDefaultSystem - (system: + outputs = { self, nixpkgs, flake-utils, gitignore, fenix, naersk }: + let + inherit (gitignore.lib) gitignoreSource; + + mkToolchain = buildPlatform: + fenix.packages.${buildPlatform}.minimal.toolchain; + + mkToolchainWithTarget = buildPlatform: targetPlatform: + with fenix.packages.${buildPlatform}; combine [ + stable.rustc + stable.cargo + targets.${targetPlatform}.stable.rust-std + ]; + + mkDevShells = buildPlatform: let - name = "himalaya"; - overlays = [ (import rust-overlay) ]; - pkgs = import nixpkgs { inherit system overlays; }; + pkgs = import nixpkgs { system = buildPlatform; }; + rust-toolchain = fenix.packages.${buildPlatform}.fromToolchainFile { + file = ./rust-toolchain.toml; + sha256 = "eMJethw5ZLrJHmoN2/l0bIyQjoTX1NsvalWSscTixpI="; + }; in - rec { - # nix build - defaultPackage = packages.${name}; - packages = { - ${name} = naersk.lib.${system}.buildPackage { - pname = name; - root = ./.; - nativeBuildInputs = with pkgs; [ openssl.dev pkg-config ]; - overrideMain = _: { - postInstall = '' - mkdir -p $out/share/applications/ - cp assets/himalaya.desktop $out/share/applications/ - ''; - }; - }; - }; - - # nix run - defaultApp = apps.${name}; - apps.${name} = utils.lib.mkApp { - inherit name; - drv = packages.${name}; - }; - - # nix develop - devShell = pkgs.mkShell { - inputsFrom = builtins.attrValues self.packages.${system}; - nativeBuildInputs = with pkgs; [ - # Nix LSP + formatter + { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + # Nix env rnix-lsp nixpkgs-fmt # Rust env - (rust-bin.fromRustupToolchainFile ./rust-toolchain.toml) - cargo-watch - rust-analyzer + rust-toolchain - # Notmuch + # notmuch notmuch ]; }; - } - ); + }; + + mkPackage = pkgs: buildPlatform: targetPlatform: package: + let + toolchain = + if isNull targetPlatform + then mkToolchain buildPlatform + else mkToolchainWithTarget buildPlatform targetPlatform; + naersk' = naersk.lib.${buildPlatform}.override { + cargo = toolchain; + rustc = toolchain; + }; + package' = { + name = "himalaya"; + src = gitignoreSource ./.; + overrideMain = _: { + postInstall = '' + mkdir -p $out/share/applications/ + cp assets/himalaya.desktop $out/share/applications/ + ''; + }; + } // pkgs.lib.optionalAttrs (!isNull targetPlatform) { + CARGO_BUILD_TARGET = targetPlatform; + } // package; + in + naersk'.buildPackage package'; + + mkPackages = buildPlatform: + let + pkgs = import nixpkgs { system = buildPlatform; }; + mkPackageWithTarget = mkPackage pkgs buildPlatform; + defaultPackage = mkPackage pkgs buildPlatform null { }; + in + { + default = defaultPackage; + linux = defaultPackage; + macos = defaultPackage; + musl = mkPackageWithTarget "x86_64-unknown-linux-musl" (with pkgs.pkgsStatic; { + CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static"; + SQLITE3_STATIC = 1; + SQLITE3_LIB_DIR = "${sqlite.out}/lib"; + hardeningDisable = [ "all" ]; + }); + # FIXME: package does not build, assembler messages: unknown + # pseudo-opā€¦ + windows = mkPackageWithTarget "x86_64-pc-windows-gnu" { + strictDeps = true; + depsBuildBuild = with pkgs.pkgsCross.mingwW64; [ + stdenv.cc + windows.pthreads + ]; + }; + }; + + mkApp = drv: flake-utils.lib.mkApp { + inherit drv; + name = "himalaya"; + }; + + mkApps = buildPlatform: { + default = mkApp self.packages.${buildPlatform}.default; + linux = mkApp self.packages.${buildPlatform}.linux; + macos = mkApp self.packages.${buildPlatform}.macos; + musl = mkApp self.packages.${buildPlatform}.musl; + windows = + let + pkgs = import nixpkgs { system = buildPlatform; }; + wine = pkgs.wine.override { wineBuild = "wine64"; }; + himalaya = self.packages.${buildPlatform}.windows; + app = pkgs.writeShellScriptBin "himalaya" '' + export WINEPREFIX="$(mktemp -d)" + ${wine}/bin/wine64 ${himalaya}/bin/himalaya.exe $@ + ''; + in + mkApp app; + }; + + in + flake-utils.lib.eachDefaultSystem (system: { + devShells = mkDevShells system; + packages = mkPackages system; + apps = mkApps system; + }); } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 292fe49..aff8cc2 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,11 @@ [toolchain] channel = "stable" +profile = "default" +components = [ + "cargo", + "clippy", + "rust-analyzer", + "rust-std", + "rustc", + "rustfmt", +]