1use std::cmp::PartialEq;
2use std::string::ToString;
3
4#[derive(
5 strum_macros::AsRefStr,
6 strum_macros::Display,
7 strum_macros::EnumDiscriminants,
8 strum_macros::IntoStaticStr,
9 Debug,
10)]
11#[repr(u16)]
12pub enum CargoMakeError {
13 #[strum(
14 to_string = "A cycle between different env variables has been detected \
15 (E001, see: https://github.com/sagiegurari/cargo-make#e001 for more information). {0}"
16 )]
17 EnvVarCycle(String) = 100,
18
19 #[strum(to_string = "Detected cycle while resolving alias {0}: {1}")]
20 AliasCycle(String, String) = 101,
21
22 #[strum(to_string = "Circular reference found for task: {0:#?}")]
23 CircularReference(String) = 102,
24
25 #[strum(to_string = "Unable to run, minimum required version is: {0}")]
26 VersionTooOld(String) = 103,
27
28 #[strum(to_string = "Error while executing command, unable to extract exit code.")]
29 ExitCodeValidation = 104,
30
31 #[strum(to_string = "Error while executing command, exit code: {0}")]
32 ExitCodeError(i32) = 105,
33
34 #[strum(to_string = "Unable to parse internal descriptor: {0}")]
35 DescriptorParseFailed(String) = 106,
36
37 #[strum(to_string = "Unable to parse external file: {0:#?}, {1}")]
38 ParseFileFailed(String, String) = 107,
39
40 #[strum(to_string = "{0}")]
41 Arity(&'static str) = 108,
42
43 #[strum(to_string = "{0}")]
44 MethodCallRestriction(&'static str) = 109,
45
46 #[strum(to_string = "Task {0:#?} is {1}")]
47 TaskIs(String, &'static str) = 110,
48
49 #[strum(to_string = "{0}")]
50 NotFound(String) = 404,
51
52 #[strum(to_string = "`std::io::Error` error. {error:?}")]
56 StdIoError { error: std::io::Error } = 700,
57
58 #[strum(to_string = "`std::fmt::Error` error. {error:?}")]
59 StdFmtError { error: std::fmt::Error } = 709,
60
61 #[strum(to_string = "{0:?}")]
62 ExitCode(std::process::ExitCode) = 710,
63
64 #[strum(to_string = "`toml::de::Error` error. {error:?}")]
65 TomlDeError { error: toml::de::Error } = 720,
66
67 #[strum(to_string = "`fsio::error::FsIOError` error. {error:?}")]
68 FsIOError { error: fsio::error::FsIOError } = 730,
69
70 #[strum(to_string = "`cliparser::types::ParserError` error. {error:?}")]
71 ParserError {
72 error: cliparser::types::ParserError,
73 } = 731,
74}
75
76impl CargoMakeError {
77 fn discriminant(&self) -> u16 {
78 unsafe { *(self as *const Self as *const u16) }
79 }
80}
81
82impl From<std::io::Error> for CargoMakeError {
83 fn from(error: std::io::Error) -> Self {
84 Self::StdIoError { error }
85 }
86}
87
88impl From<std::fmt::Error> for CargoMakeError {
89 fn from(error: std::fmt::Error) -> Self {
90 Self::StdFmtError { error }
91 }
92}
93
94impl From<toml::de::Error> for CargoMakeError {
95 fn from(error: toml::de::Error) -> Self {
96 Self::TomlDeError { error }
97 }
98}
99
100impl From<fsio::error::FsIOError> for CargoMakeError {
101 fn from(error: fsio::error::FsIOError) -> Self {
102 Self::FsIOError { error }
103 }
104} impl From<cliparser::types::ParserError> for CargoMakeError {
107 fn from(error: cliparser::types::ParserError) -> Self {
108 Self::ParserError { error }
109 }
110}
111
112impl From<std::process::ExitCode> for CargoMakeError {
113 fn from(error: std::process::ExitCode) -> Self {
114 Self::ExitCode(error)
115 }
116}
117
118impl std::process::Termination for CargoMakeError {
119 fn report(self) -> std::process::ExitCode {
120 if let CargoMakeError::ExitCode(exit_code) = self {
121 return exit_code;
122 }
123 let status_code = self.discriminant();
124 if status_code > u8::MAX as u16 {
125 eprintln!("exit code {}", status_code);
126 std::process::ExitCode::FAILURE
127 } else {
128 std::process::ExitCode::from(status_code as u8)
129 }
130 }
131}
132
133pub enum SuccessOrCargoMakeError<T> {
134 Ok(T),
135 Err(CargoMakeError),
136}
137
138impl<T> From<Result<T, CargoMakeError>> for SuccessOrCargoMakeError<T> {
139 fn from(value: Result<T, CargoMakeError>) -> Self {
140 match value {
141 Ok(val) => SuccessOrCargoMakeError::Ok(val),
142 Err(error) => SuccessOrCargoMakeError::Err(error),
143 }
144 }
145}
146
147impl<T: std::any::Any> std::process::Termination for SuccessOrCargoMakeError<T> {
150 fn report(self) -> std::process::ExitCode {
151 const PROCESS_EXIT_CODE: fn(i32) -> std::process::ExitCode = |e: i32| {
152 if e > u8::MAX as i32 {
153 eprintln!("exit code {}", e);
154 std::process::ExitCode::FAILURE
155 } else {
156 std::process::ExitCode::from(e as u8)
157 }
158 };
159
160 match self {
161 SuccessOrCargoMakeError::Ok(e)
162 if std::any::TypeId::of::<T>()
163 == std::any::TypeId::of::<std::process::ExitCode>() =>
164 {
165 *(&e as &dyn std::any::Any)
166 .downcast_ref::<std::process::ExitCode>()
167 .unwrap()
168 }
169 SuccessOrCargoMakeError::Ok(_) => std::process::ExitCode::SUCCESS,
170 SuccessOrCargoMakeError::Err(err) => match err {
171 CargoMakeError::StdIoError { error } if error.raw_os_error().is_some() => {
172 let e = unsafe { error.raw_os_error().unwrap_unchecked() };
173 eprintln!("{}", e.to_string());
174 PROCESS_EXIT_CODE(e)
175 }
176 CargoMakeError::ExitCode(error) => error,
177 _ => {
178 eprintln!("{}", err.to_string());
179 PROCESS_EXIT_CODE(err.discriminant() as i32)
180 }
181 },
182 }
183 }
184}