Composers and readers did not work as expected. It is just not possible for himalaya to spawn a command that spawns $EDITOR, piping and redirection cannot satisfy all the needs. Either the $EDITOR does not spawn (hangs over), either himalaya does not collect any output from edition. The simplest way is to use an intermediate temp file, or use process substitution. For eg., using mml: mml compose >(himalaya message send) You can also write into a file then feed himalaya with it.
5.0 KiB
Contributing guide
Thank you for investing your time in contributing to Himalaya CLI.
Development environment
The development environment is managed by Nix flakes. Running nix develop (or nix-shell for non-flake users) spawns a shell with the right Rust toolchain, cargo-deny, pkg-config and the OpenSSL / DBus libraries.
If you do not want to use Nix, install rustup and pull the toolchain pinned by rust-version in Cargo.toml:
rustup update
cargo(>=v1.87)rustc(>=v1.87, edition 2024)
Build
cargo build
You can disable default features with --no-default-features and enable individual features with --features feat1,feat2.
For example, an IMAP+SMTP-only release build:
cargo build --no-default-features --features imap,smtp,rustls-ring --release
The release profile ([profile.release] in Cargo.toml) sets lto = "fat", codegen-units = 1, strip = "symbols" and panic = "abort" to keep the binary small.
Project layout
Himalaya CLI is the command-line front-end of the Pimalaya project. Most of the work happens in companion crates rather than in this repository:
- io-email: cross-protocol email client (
EmailClientStd, sharedEnvelope/Mailbox/Flag/Addresstypes, search DSL). - io-imap, io-jmap, io-maildir, io-smtp: per-protocol I/O-free coroutines plus the std-blocking clients that drive them.
- io-http: I/O-free HTTP request/response state machines used by JMAP and the discovery wizard.
- pimconf: PIM service discovery (PACC, Thunderbird Autoconfiguration, RFC 6186 SRV) consumed by the wizard.
- pimalaya/stream: TCP / TLS / SASL plumbing shared by all std clients.
- pimalaya/cli: cross-binary CLI helpers (printer, prompt, wizard primitives, clap args, build-time env, spinner).
- pimalaya/config: TOML configuration loader and shell-expanded secrets.
- pimalaya/mml: MIME Meta Language composer / interpreter, chained into
messages send/messages addvia a tempfile or shell process substitution. - pimalaya/sirup: session re-use over a Unix socket (pair with
imap.server/smtp.serverto amortize TLS handshakes). - pimalaya/ortie: standalone OAuth 2.0 token broker (replaces v1's bundled
oauth-lib). - pimalaya/mimosa: standalone secret manager (replaces v1's bundled
keyring-lib).
Bugs touching protocol semantics usually live in the matching io-* crate; rendering, composition and CLI surface live here.
Override dependencies
Cargo.toml already patches every Pimalaya crate to its git remote so the working copy compiles against the latest master of each lib:
[patch.crates-io]
io-email.git = "https://github.com/pimalaya/io-email"
io-http.git = "https://github.com/pimalaya/io-http"
io-imap.git = "https://github.com/pimalaya/io-imap"
io-jmap.git = "https://github.com/pimalaya/io-jmap"
io-maildir.git = "https://github.com/pimalaya/io-maildir"
io-smtp.git = "https://github.com/pimalaya/io-smtp"
pimalaya-cli.git = "https://github.com/pimalaya/cli"
pimalaya-config.git = "https://github.com/pimalaya/config"
pimalaya-stream.git = "https://github.com/pimalaya/stream"
pimconf.git = "https://github.com/pimalaya/pimconf"
To build against a local checkout of one of those crates, swap the matching .git = "..." for .path = "../<repo>". For example, with io-email next to himalaya:
[patch.crates-io]
io-email.path = "../io-email"
If cargo complains about "perhaps two different versions of crate X are being used", patch every Pimalaya crate that pulls X transitively so the dep graph converges on the local copies:
[patch.crates-io]
io-email.path = "../io-email"
io-http.path = "../io-http"
io-imap.path = "../io-imap"
io-jmap.path = "../io-jmap"
io-maildir.path = "../io-maildir"
io-smtp.path = "../io-smtp"
pimalaya-cli.path = "../cli"
pimalaya-config.path = "../config"
pimalaya-stream.path = "../stream"
pimconf.path = "../pimconf"
Lint, test, audit
cargo fmt
cargo clippy --all-features --all-targets
cargo test --all-features
cargo deny check
cargo deny runs against the rules in deny.toml (license allow-list and allowed git sources).
Commit style
Himalaya CLI follows the conventional commits specification. Prefix every commit with one of feat, fix, refactor, docs, chore, test, ci, build, optionally scoped (fix(imap): ...).