Skip to main content

aperture_cli/cli/
errors.rs

1//! Error display formatting for the CLI.
2
3use crate::constants;
4use crate::error::Error;
5
6/// Prints an error message, either as JSON or user-friendly format.
7pub fn print_error_with_json(error: &Error, json_format: bool) {
8    if !json_format {
9        print_error(error);
10        return;
11    }
12    let json_error = error.to_json();
13    let Ok(json_output) = serde_json::to_string_pretty(&json_error) else {
14        print_error(error);
15        return;
16    };
17    eprintln!("{json_output}");
18}
19
20/// Prints a user-friendly error message with context and suggestions.
21#[allow(clippy::too_many_lines)]
22pub fn print_error(error: &Error) {
23    match error {
24        Error::Internal {
25            kind,
26            message,
27            context,
28        } => {
29            eprintln!("{kind}: {message}");
30            let Some(ctx) = context else { return };
31            if let Some(suggestion) = &ctx.suggestion {
32                eprintln!("\nHint: {suggestion}");
33            }
34        }
35        Error::Io(io_err) => match io_err.kind() {
36            std::io::ErrorKind::NotFound => {
37                eprintln!(
38                    "File Not Found\n{io_err}\n\nHint: {}",
39                    constants::ERR_FILE_NOT_FOUND
40                );
41            }
42            std::io::ErrorKind::PermissionDenied => {
43                eprintln!(
44                    "Permission Denied\n{io_err}\n\nHint: {}",
45                    constants::ERR_PERMISSION
46                );
47            }
48            _ => eprintln!("File System Error\n{io_err}"),
49        },
50        Error::Network(req_err) => {
51            if req_err.is_connect() {
52                eprintln!(
53                    "Connection Error\n{req_err}\n\nHint: {}",
54                    constants::ERR_CONNECTION
55                );
56                return;
57            }
58            if req_err.is_timeout() {
59                eprintln!(
60                    "Timeout Error\n{req_err}\n\nHint: {}",
61                    constants::ERR_TIMEOUT
62                );
63                return;
64            }
65            if !req_err.is_status() {
66                eprintln!("Network Error\n{req_err}");
67                return;
68            }
69            let Some(status) = req_err.status() else {
70                eprintln!("Network Error\n{req_err}");
71                return;
72            };
73            match status.as_u16() {
74                401 => eprintln!(
75                    "Authentication Error\n{req_err}\n\nHint: {}",
76                    constants::ERR_API_CREDENTIALS
77                ),
78                403 => eprintln!(
79                    "Permission Error\n{req_err}\n\nHint: {}",
80                    constants::ERR_PERMISSION_DENIED
81                ),
82                404 => eprintln!(
83                    "Not Found Error\n{req_err}\n\nHint: {}",
84                    constants::ERR_ENDPOINT_NOT_FOUND
85                ),
86                429 => eprintln!(
87                    "Rate Limited\n{req_err}\n\nHint: {}",
88                    constants::ERR_RATE_LIMITED
89                ),
90                500..=599 => eprintln!(
91                    "Server Error\n{req_err}\n\nHint: {}",
92                    constants::ERR_SERVER_ERROR
93                ),
94                _ => eprintln!("HTTP Error\n{req_err}"),
95            }
96        }
97        Error::Yaml(yaml_err) => {
98            eprintln!(
99                "YAML Parsing Error\n{yaml_err}\n\nHint: {}",
100                constants::ERR_YAML_SYNTAX
101            );
102        }
103        Error::Json(json_err) => {
104            eprintln!(
105                "JSON Parsing Error\n{json_err}\n\nHint: {}",
106                constants::ERR_JSON_SYNTAX
107            );
108        }
109        Error::Toml(toml_err) => {
110            eprintln!(
111                "TOML Parsing Error\n{toml_err}\n\nHint: {}",
112                constants::ERR_TOML_SYNTAX
113            );
114        }
115        Error::Anyhow(anyhow_err) => {
116            eprintln!("Error\n{anyhow_err}");
117        }
118    }
119}