Add comprehensive dry-run functionality to the Rust implementation that allows users to test their configuration without making any changes to CouchDB: - Added --dry-run/-n command line flag with clap argument parsing - Extended CommandLineArgs struct with dry_run field - Updated bash completion script to include new flag - Comprehensive dry-run logic throughout sync coordinator: - Skip database creation with informative logging - Skip sync metadata retrieval and use config fallback - Skip deleted message handling in sync mode - Skip message and attachment storage with detailed simulation - Skip sync metadata updates with summary information - Enhanced summary output to clearly indicate dry-run vs normal mode - Updated all tests to include new dry_run field - Maintains all IMAP operations for realistic mail discovery testing This brings the Rust implementation to feature parity with the Go version for safe configuration testing as identified in ANALYSIS.md. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
125 lines
No EOL
4.1 KiB
Rust
125 lines
No EOL
4.1 KiB
Rust
//! 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("dry-run")
|
|
.short('n')
|
|
.long("dry-run")
|
|
.help("Show what would be done without making any changes")
|
|
.action(ArgAction::SetTrue))
|
|
.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(),
|
|
dry_run: matches.get_flag("dry-run"),
|
|
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 -n --dry-run -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
|
|
}
|
|
} |