Skip to main content

cvkg_cli/
error.rs

1//! CLI error types for user-friendly error reporting.
2
3use std::fmt;
4
5/// Errors that can occur during CLI operations.
6#[derive(Debug)]
7pub enum CliError {
8    /// File I/O error.
9    Io(std::io::Error),
10    /// Command execution failed {
11    CommandFailed { command: String, exit_code: i32 },
12    /// Invalid user input.
13    InvalidInput { message: String },
14    /// Crate operation error.
15    CrateError { name: String, message: String },
16    /// Build error with parsed cargo output.
17    BuildError {
18        message: String,
19        file: Option<String>,
20        line: Option<u32>,
21        column: Option<u32>,
22    },
23    /// General error with message.
24    Other(String),
25}
26
27impl fmt::Display for CliError {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        match self {
30            CliError::Io(e) => write!(f, "I/O error: {}", e),
31            CliError::CommandFailed { command, exit_code } => {
32                write!(
33                    f,
34                    "Command '{}' failed with exit code {}",
35                    command, exit_code
36                )
37            }
38            CliError::InvalidInput { message } => write!(f, "Invalid input: {}", message),
39            CliError::CrateError { name, message } => {
40                write!(f, "Crate '{}' error: {}", name, message)
41            }
42            CliError::BuildError {
43                message,
44                file,
45                line,
46                column,
47            } => {
48                write!(f, "Build error: {}", message)?;
49                if let Some(file) = file {
50                    write!(f, " ({})", file)?;
51                    if let Some(line) = line {
52                        write!(f, ":{}", line)?;
53                        if let Some(col) = column {
54                            write!(f, ":{}", col)?;
55                        }
56                    }
57                }
58                Ok(())
59            }
60            CliError::Other(msg) => write!(f, "{}", msg),
61        }
62    }
63}
64
65impl std::error::Error for CliError {
66    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
67        match self {
68            CliError::Io(e) => Some(e),
69            _ => None,
70        }
71    }
72}
73
74impl From<std::io::Error> for CliError {
75    fn from(e: std::io::Error) -> Self {
76        CliError::Io(e)
77    }
78}
79
80impl From<String> for CliError {
81    fn from(s: String) -> Self {
82        CliError::Other(s)
83    }
84}
85
86impl From<&str> for CliError {
87    fn from(s: &str) -> Self {
88        CliError::Other(s.to_string())
89    }
90}
91
92impl From<cvkg_core::error_types::CvkgError> for CliError {
93    fn from(e: cvkg_core::error_types::CvkgError) -> Self {
94        CliError::Other(e.to_string())
95    }
96}
97
98/// Print a user-friendly error message and exit with code 1.
99pub fn exit_with_error(error: CliError) -> ! {
100    use console::style;
101    eprintln!("{} {}", style("❌").red(), error);
102    std::process::exit(1);
103}