feat: implement complete Rust version of mail2couch
- Add comprehensive Rust implementation matching Go functionality - Configuration loading with automatic file discovery - GNU-style command line parsing with clap (--config/-c, --max-messages/-m) - CouchDB client integration with document storage and sync metadata - IMAP client functionality with message fetching and parsing - Folder filtering with wildcard pattern support (*, ?, [abc]) - Message filtering by subject, sender, and recipient keywords - Incremental sync functionality with metadata tracking - Bash completion generation matching Go implementation - Cross-compatible document schemas and database structures - Successfully tested with existing test environment Note: TLS support and advanced email parsing features pending 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
88a5bfb42b
commit
4835df070e
9 changed files with 1901 additions and 8 deletions
119
rust/src/cli.rs
Normal file
119
rust/src/cli.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
//! Command line interface for mail2couch
|
||||
//!
|
||||
//! This module handles command line argument parsing and bash completion generation,
|
||||
//! matching the behavior of the Go implementation.
|
||||
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::config::CommandLineArgs;
|
||||
|
||||
/// Parse command line arguments using GNU-style options
|
||||
pub fn parse_command_line() -> CommandLineArgs {
|
||||
let app = Command::new("mail2couch")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about("Email backup utility for CouchDB")
|
||||
.long_about("A powerful email backup utility that synchronizes mail from IMAP accounts to CouchDB databases with intelligent incremental sync, comprehensive filtering, and native attachment support.")
|
||||
.arg(Arg::new("config")
|
||||
.short('c')
|
||||
.long("config")
|
||||
.value_name("FILE")
|
||||
.help("Path to configuration file")
|
||||
.action(ArgAction::Set))
|
||||
.arg(Arg::new("max-messages")
|
||||
.short('m')
|
||||
.long("max-messages")
|
||||
.value_name("N")
|
||||
.help("Maximum number of messages to process per mailbox per run (0 = no limit)")
|
||||
.value_parser(clap::value_parser!(u32))
|
||||
.action(ArgAction::Set))
|
||||
.arg(Arg::new("generate-bash-completion")
|
||||
.long("generate-bash-completion")
|
||||
.help("Generate bash completion script and exit")
|
||||
.action(ArgAction::SetTrue));
|
||||
|
||||
let matches = app.get_matches();
|
||||
|
||||
// Handle bash completion generation
|
||||
if matches.get_flag("generate-bash-completion") {
|
||||
generate_bash_completion();
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
CommandLineArgs {
|
||||
config_path: matches.get_one::<String>("config").map(|s| s.clone()),
|
||||
max_messages: matches.get_one::<u32>("max-messages").copied(),
|
||||
generate_bash_completion: matches.get_flag("generate-bash-completion"),
|
||||
help: false, // Using clap's built-in help
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate bash completion script for mail2couch
|
||||
pub fn generate_bash_completion() {
|
||||
let app_name = env::args().next()
|
||||
.map(|path| {
|
||||
Path::new(&path).file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.unwrap_or("mail2couch")
|
||||
.to_string()
|
||||
})
|
||||
.unwrap_or_else(|| "mail2couch".to_string());
|
||||
|
||||
let script = format!(r#"#!/bin/bash
|
||||
# Bash completion script for {}
|
||||
# Generated automatically by {} --generate-bash-completion
|
||||
|
||||
_{}_completions() {{
|
||||
local cur prev words cword
|
||||
_init_completion || return
|
||||
|
||||
case $prev in
|
||||
-c|--config)
|
||||
# Complete config files (*.json)
|
||||
_filedir "json"
|
||||
return
|
||||
;;
|
||||
-m|--max-messages)
|
||||
# Complete with numbers, suggest common values
|
||||
COMPREPLY=($(compgen -W "10 50 100 500 1000" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $cur == -* ]]; then
|
||||
# Complete with available options
|
||||
local opts="-c --config -m --max-messages -h --help --generate-bash-completion"
|
||||
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
|
||||
return
|
||||
fi
|
||||
|
||||
# No default completion for other cases
|
||||
}}
|
||||
|
||||
# Register the completion function
|
||||
complete -F _{}_completions {}
|
||||
|
||||
# Enable completion for common variations of the command name
|
||||
if [[ "$({} --help 2>/dev/null)" =~ "mail2couch" ]]; then
|
||||
complete -F _{}_completions mail2couch
|
||||
fi
|
||||
"#, app_name, app_name, app_name, app_name, app_name, app_name, app_name);
|
||||
|
||||
print!("{}", script);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_bash_completion_generation() {
|
||||
// Test that bash completion generation doesn't panic
|
||||
// This is a basic smoke test
|
||||
let _output = std::panic::catch_unwind(|| {
|
||||
generate_bash_completion();
|
||||
});
|
||||
// Just verify it doesn't panic, we can't easily test the output without capturing stdout
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue