11//! Command Handlers Module
22//!
3- //! This module provides unified command execution and error handling for all CLI commands.
4- //! It serves as the central dispatch point for command execution and provides consistent
5- //! error handling across all commands.
6-
7- use std:: sync:: { Arc , Mutex } ;
8-
9- use crate :: presentation:: errors:: CommandError ;
10- use crate :: presentation:: input:: cli:: Commands ;
11- use crate :: presentation:: user_output:: UserOutput ;
3+ //! This module provides command execution and error handling for CLI commands.
4+ //!
5+ //! **Note**: The main execution logic has been moved to the Dispatch Layer.
6+ //! See `crate::presentation::dispatch` for the current command routing implementation.
127
138// Re-export command modules
149pub mod constants;
@@ -25,187 +20,3 @@ pub mod tests;
2520// pub mod provision;
2621// pub mod configure;
2722// pub mod release;
28-
29- /// Execute the given command
30- ///
31- /// **DEPRECATED**: This function is deprecated in favor of the new Dispatch Layer.
32- /// Use `crate::presentation::dispatch::route_command` instead.
33- ///
34- /// This function will be removed in a future version. The new dispatch layer
35- /// provides better separation of concerns and cleaner architecture.
36- ///
37- /// # Migration Guide
38- ///
39- /// Old code:
40- /// ```rust,ignore
41- /// use std::sync::{Arc, Mutex};
42- /// use crate::presentation::{commands, user_output::UserOutput};
43- ///
44- /// let user_output = Arc::new(Mutex::new(UserOutput::new(/* ... */)));
45- /// commands::execute(command, working_dir, &user_output)?;
46- /// ```
47- ///
48- /// New code:
49- /// ```rust,ignore
50- /// use std::sync::Arc;
51- /// use crate::bootstrap::Container;
52- /// use crate::presentation::dispatch::{route_command, ExecutionContext};
53- ///
54- /// let container = Arc::new(Container::new());
55- /// let context = ExecutionContext::new(container);
56- /// route_command(command, working_dir, &context)?;
57- /// ```
58- ///
59- /// This function serves as the central dispatcher for all CLI commands.
60- /// It matches the command type and delegates execution to the appropriate
61- /// command handler module.
62- ///
63- /// # Arguments
64- ///
65- /// * `command` - The parsed CLI command to execute
66- /// * `working_dir` - Working directory for environment data storage
67- /// * `user_output` - Shared user output service for consistent output formatting
68- ///
69- /// # Returns
70- ///
71- /// Returns `Ok(())` on successful execution, or a `CommandError` if execution fails.
72- /// The error contains detailed context and actionable troubleshooting information.
73- ///
74- /// # Errors
75- ///
76- /// Returns an error if command execution fails.
77- ///
78- /// # Example
79- ///
80- /// ```rust
81- /// use clap::Parser;
82- /// use torrust_tracker_deployer_lib::presentation::{input::cli, commands, user_output};
83- /// use std::{path::Path, sync::{Arc, Mutex}};
84- ///
85- /// let cli = cli::Cli::parse();
86- /// if let Some(command) = cli.command {
87- /// let working_dir = Path::new(".");
88- /// let user_output = Arc::new(Mutex::new(user_output::UserOutput::new(user_output::VerbosityLevel::Normal)));
89- /// let result = commands::execute(command, working_dir, &user_output);
90- /// match result {
91- /// Ok(_) => println!("Command executed successfully"),
92- /// Err(e) => commands::handle_error(&e, &user_output),
93- /// }
94- /// }
95- /// ```
96- #[ deprecated(
97- since = "0.1.0" ,
98- note = "Use `crate::presentation::dispatch::route_command` instead"
99- ) ]
100- ///
101- /// ```rust
102- /// use clap::Parser;
103- /// use torrust_tracker_deployer_lib::presentation::{input::cli, commands, user_output};
104- /// use std::{path::Path, sync::{Arc, Mutex}};
105- ///
106- /// let cli = cli::Cli::parse();
107- /// if let Some(command) = cli.command {
108- /// let working_dir = Path::new(".");
109- /// let user_output = Arc::new(Mutex::new(user_output::UserOutput::new(user_output::VerbosityLevel::Normal)));
110- /// let result = commands::execute(command, working_dir, &user_output);
111- /// match result {
112- /// Ok(_) => println!("Command executed successfully"),
113- /// Err(e) => commands::handle_error(&e, &user_output),
114- /// }
115- /// }
116- /// ```
117- pub fn execute (
118- command : Commands ,
119- working_dir : & std:: path:: Path ,
120- user_output : & Arc < Mutex < UserOutput > > ,
121- ) -> Result < ( ) , CommandError > {
122- match command {
123- Commands :: Create { action } => {
124- create:: handle_create_command ( action, working_dir, user_output) ?;
125- Ok ( ( ) )
126- }
127- Commands :: Destroy { environment } => {
128- destroy:: handle_destroy_command ( & environment, working_dir, user_output) ?;
129- Ok ( ( ) )
130- } // Future commands will be added here:
131- //
132- // Commands::Provision { environment, provider } => {
133- // provision::handle(&environment, &provider)?;
134- // Ok(())
135- // }
136- //
137- // Commands::Configure { environment } => {
138- // configure::handle(&environment)?;
139- // Ok(())
140- // }
141- //
142- // Commands::Release { environment, version } => {
143- // release::handle(&environment, &version)?;
144- // Ok(())
145- // }
146- }
147- }
148-
149- /// Handle command errors with consistent user output
150- ///
151- /// This function provides standardized error output for all command failures.
152- /// It displays the error message and detailed troubleshooting information
153- /// to help users resolve issues.
154- ///
155- /// # Arguments
156- ///
157- /// * `error` - The command error to handle and display
158- /// * `user_output` - Shared user output service for consistent output formatting
159- ///
160- /// # Example
161- ///
162- /// ```rust
163- /// use clap::Parser;
164- /// use torrust_tracker_deployer_lib::presentation::{commands, input::cli, errors, user_output};
165- /// use torrust_tracker_deployer_lib::presentation::commands::destroy::DestroySubcommandError;
166- /// use torrust_tracker_deployer_lib::domain::environment::name::EnvironmentNameError;
167- /// use std::sync::{Arc, Mutex};
168- ///
169- /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
170- /// // Example of handling a command error (simulated for testing)
171- /// let name_error = EnvironmentNameError::InvalidFormat {
172- /// attempted_name: "invalid_name".to_string(),
173- /// reason: "contains invalid characters: _".to_string(),
174- /// valid_examples: vec!["dev".to_string(), "staging".to_string()],
175- /// };
176- /// let sample_error = errors::CommandError::Destroy(
177- /// Box::new(DestroySubcommandError::InvalidEnvironmentName {
178- /// name: "invalid_name".to_string(),
179- /// source: name_error,
180- /// })
181- /// );
182- /// let user_output = Arc::new(Mutex::new(user_output::UserOutput::new(user_output::VerbosityLevel::Normal)));
183- /// commands::handle_error(&sample_error, &user_output);
184- /// # Ok(())
185- /// # }
186- /// ```
187- pub fn handle_error ( error : & CommandError , user_output : & Arc < Mutex < UserOutput > > ) {
188- let help_text = error. help ( ) ;
189-
190- if let Ok ( mut output) = user_output. lock ( ) {
191- output. error ( & format ! ( "{error}" ) ) ;
192- output. blank_line ( ) ;
193- output. info_block ( "For detailed troubleshooting:" , & [ help_text] ) ;
194- } else {
195- // Cannot acquire lock - print to stderr directly as fallback
196- //
197- // RATIONALE: Plain text formatting without emojis/styling is intentional.
198- // When the mutex is poisoned, we're in a degraded error state where another
199- // thread has panicked. Using plain eprintln! ensures maximum compatibility
200- // and avoids any additional complexity that could fail in this critical path.
201- // The goal here is reliability over aesthetics - get the error message to
202- // the user no matter what, even if it's not pretty.
203- eprintln ! ( "ERROR: {error}" ) ;
204- eprintln ! ( ) ;
205- eprintln ! ( "CRITICAL: Failed to acquire user output lock." ) ;
206- eprintln ! ( "This indicates a panic occurred in another thread." ) ;
207- eprintln ! ( ) ;
208- eprintln ! ( "For detailed troubleshooting:" ) ;
209- eprintln ! ( "{help_text}" ) ;
210- }
211- }
0 commit comments