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:
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();