crabmail

Static HTML email archive viewer in Rust
git clone git://git.alexwennerberg.com/crabmail
Log | Files | Refs | README | LICENSE

commit a6fdcab6c90e9cd22df6ba7cb8ec978c9d8e540a
parent b725166ed2279d6b7b58a52239e57b4d7b9d5b9c
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Fri, 24 Dec 2021 12:30:32 -0800

Replace pico-args with in-house parser

Diffstat:
MCargo.lock | 7-------
MCargo.toml | 1-
Asrc/arg.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.rs | 31++++++-------------------------
4 files changed, 83 insertions(+), 33 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -48,7 +48,6 @@ dependencies = [ "linkify", "mailparse", "once_cell", - "pico-args", "sha3", "urlencoding", ] @@ -137,12 +136,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - -[[package]] name = "quoted_printable" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -13,6 +13,5 @@ horrorshow = "0.8" linkify = "0.8" mailparse = "0.13" once_cell = "1.9" -pico-args = "0.4" sha3 = "0.10" urlencoding = "2.1" diff --git a/src/arg.rs b/src/arg.rs @@ -0,0 +1,77 @@ +// Extremely minimalist command line interface, inspired by +// [sbase](https://git.suckless.org/sbase/)'s +// [arg.h](https://git.suckless.org/sbase/file/arg.h.html) +// +// I believe this has the same behavior, which is: +// * flags can be grouped (-abc) +// * missing arg -> print usage, exit +// * invalid flag -> print usage, exit +// +// This is, of course, aggressively minimalist, perhaps even too much so. +// +// Copy/paste this code and you have a CLI! No library needed! + +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; +use std::process::exit; + +fn usage() -> ! { + let name = env::args().next().unwrap(); + eprintln!( + "usage: {} [mbox-file] + +ARGS: +-c config file (crabmail.conf) +-d output directory (site)", + name + ); + exit(1) +} + +pub struct Args { + pub mbox: PathBuf, + pub config: PathBuf, + pub out_dir: PathBuf, +} + +impl Args { + pub fn from_env() -> Self { + // Modify as needed + // let mut flags = String::new(); + let mut mbox: Option<String> = None; + let mut out_dir = "site".into(); + let mut config = PathBuf::from("crabmail.conf"); + + let mut args = env::args().skip(1); + + // Doesn't support non-UTF-8 paths TODO: solution? + // See https://github.com/RazrFalcon/pico-args/issues/2 + let parsenext = + |a: Option<String>| a.and_then(|a| a.parse().ok()).unwrap_or_else(|| usage()); + + while let Some(arg) = args.next() { + let mut chars = arg.chars(); + if chars.next() != Some('-') { + mbox = Some(arg); + continue; + } + chars.for_each(|m| match m { + 'c' => config = parsenext(args.next()), + 'd' => out_dir = parsenext(args.next()), + // 'a' | 'b' => flags.push(m), + _ => { + usage(); + } + }) + } + Self { + config, + mbox: match mbox { + Some(m) => m.into(), + None => usage(), + }, + out_dir, + } + } +} diff --git a/src/main.rs b/src/main.rs @@ -22,6 +22,7 @@ use urlencoding; use config::{Config, INSTANCE}; use utils::xml_safe; +mod arg; mod config; mod mbox; mod time; @@ -459,35 +460,15 @@ fn local_parse_email(data: &[u8]) -> Result<Email> { }); } -const HELP: &str = "\ -Usage: crabmail - --m --mbox input mbox file --c --config config file [crabmail.conf] --d --dir output directory [site] -"; - fn main() -> Result<()> { - let mut pargs = pico_args::Arguments::from_env(); + let mut args = arg::Args::from_env(); - if pargs.contains(["-h", "--help"]) { - print!("{}", HELP); - std::process::exit(0); - } - // TODO configurable - let out_dir = pargs - .opt_value_from_os_str(["-d", "--dir"], parse_path)? - .unwrap_or("site".into()); - let config_file = pargs - .opt_value_from_os_str(["-c", "--config"], parse_path)? - .unwrap_or("crabmail.conf".into()); - let in_mbox = pargs.value_from_os_str(["-m", "--mbox"], parse_path)?; - - let mut config = Config::from_file(&config_file).unwrap(); // TODO better err handling - config.out_dir = out_dir.to_owned(); + let mut config = Config::from_file(&args.config).unwrap(); // TODO better err handling + config.out_dir = args.out_dir; INSTANCE.set(config).unwrap(); + let out_dir = &Config::global().out_dir; - let mbox = mbox::from_file(&in_mbox)?; + let mbox = mbox::from_file(&args.mbox)?; let mut thread_index: HashMap<String, Vec<String>> = HashMap::new();