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>
95 lines
No EOL
2.9 KiB
Rust
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);
|
|
}
|
|
}
|
|
}
|
|
} |