mail2couch/rust/src/main.rs
Ole-Morten Duesund 322fb094a5 feat: add --dry-run mode to Rust implementation
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>
2025-08-03 18:26:01 +02:00

95 lines
No EOL
2.9 KiB
Rust

use anyhow::Result;
use env_logger::Env;
use log::{error, info};
use mail2couch::{
cli::parse_command_line,
config::Config,
sync::SyncCoordinator,
};
use std::process;
#[tokio::main]
async fn main() {
// Initialize logging
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
// Parse command line arguments
let args = parse_command_line();
// Run the main application
if let Err(e) = run(args).await {
error!("❌ Application failed: {}", e);
process::exit(1);
}
}
async fn run(args: mail2couch::config::CommandLineArgs) -> Result<()> {
info!("🚀 Starting mail2couch Rust implementation");
// Load configuration with automatic discovery
let (config, config_path) = Config::load_with_discovery(&args)?;
info!("Using configuration file: {}", config_path.display());
if let Some(max) = args.max_messages {
info!("Maximum messages per mailbox: {}", max);
} else {
info!("Maximum messages per mailbox: unlimited");
}
if args.dry_run {
info!("🔍 DRY-RUN MODE: No changes will be made to CouchDB");
}
// Display configuration summary
print_config_summary(&config);
// Create sync coordinator
let mut coordinator = SyncCoordinator::new(config, args)?;
// Test all connections before starting sync
info!("Testing connections...");
coordinator.test_connections().await?;
// Perform synchronization
info!("Starting synchronization...");
let results = coordinator.sync_all_sources().await?;
// Print summary
coordinator.print_sync_summary(&results);
info!("🎉 mail2couch completed successfully!");
Ok(())
}
fn print_config_summary(config: &mail2couch::config::Config) {
info!("Configuration summary:");
info!(" CouchDB: {}", config.couch_db.url);
info!(" Mail sources: {}", config.mail_sources.len());
for (i, source) in config.mail_sources.iter().enumerate() {
let status = if source.enabled { "enabled" } else { "disabled" };
info!(
" {}: {} ({}) - {} ({})",
i + 1,
source.name,
source.user,
source.host,
status
);
if source.enabled {
if !source.folder_filter.include.is_empty() {
info!(" Include folders: {:?}", source.folder_filter.include);
}
if !source.folder_filter.exclude.is_empty() {
info!(" Exclude folders: {:?}", source.folder_filter.exclude);
}
if source.message_filter.since.is_some() {
info!(" Since: {:?}", source.message_filter.since);
}
if !source.message_filter.subject_keywords.is_empty() {
info!(" Subject keywords: {:?}", source.message_filter.subject_keywords);
}
}
}
}