Skip to main content

torrust_tracker_deployer_lib/bootstrap/
app.rs

1//! Main Application Bootstrap
2//!
3//! This module provides a thin bootstrap layer for the Torrust Tracker Deployer CLI.
4//! It handles application initialization, logging setup, and command dispatch while
5//! delegating all CLI parsing and business logic to the presentation layer.
6//!
7//! ## Responsibilities
8//!
9//! - **Application Lifecycle**: Initialize and shutdown the application
10//! - **Logging Setup**: Configure logging based on CLI arguments
11//! - **Command Dispatch**: Route commands to the presentation layer for execution
12//! - **Exit Handling**: Manage application exit codes and cleanup
13//!
14//! ## Design Principles
15//!
16//! - **Thin Layer**: Minimal logic, maximum delegation to appropriate layers
17//! - **Single Responsibility**: Focus only on application bootstrap concerns
18//! - **Clean Separation**: No CLI parsing or business logic in this module
19
20use std::sync::Arc;
21
22use clap::Parser;
23use tracing::info;
24
25use crate::bootstrap;
26use crate::presentation::cli::dispatch::route_command;
27use crate::presentation::cli::dispatch::ExecutionContext;
28use crate::presentation::cli::error::handle_error;
29use crate::presentation::cli::Cli;
30
31/// Main application entry point
32///
33/// This function serves as the application bootstrap, handling:
34/// 1. CLI argument parsing (delegated to presentation layer)
35/// 2. Logging initialization using `LoggingConfig`
36/// 3. Service container creation for dependency injection
37/// 4. Command execution (delegated to presentation layer)
38/// 5. Error handling and exit code management
39///
40/// # Panics
41///
42/// This function will panic if:
43/// - Log directory cannot be created (filesystem permissions issue)
44/// - Logging initialization fails (usually means it was already initialized)
45///
46/// Both panics are intentional as logging is critical for observability.
47pub async fn run() {
48    let cli = Cli::parse();
49
50    let logging_config = cli.global.logging_config();
51
52    bootstrap::logging::init_subscriber(logging_config);
53
54    info!(
55        app = "torrust-tracker-deployer",
56        version = env!("CARGO_PKG_VERSION"),
57        log_dir = %cli.global.log_dir.display(),
58        log_file_format = ?cli.global.log_file_format,
59        log_stderr_format = ?cli.global.log_stderr_format,
60        log_output = ?cli.global.log_output,
61        "Application started"
62    );
63
64    // Initialize service container for dependency injection
65    let container = Arc::new(bootstrap::Container::new(
66        cli.global.verbosity_level(),
67        &cli.global.working_dir,
68    ));
69    let context = ExecutionContext::new(container, cli.global.clone());
70
71    match cli.command {
72        Some(command) => {
73            if let Err(e) = route_command(command, &cli.global.working_dir, &context).await {
74                handle_error(&e, &context.user_output());
75                std::process::exit(1);
76            }
77        }
78        None => {
79            bootstrap::help::display_getting_started();
80        }
81    }
82
83    info!("Application finished");
84}