cargo/util/
errors.rs
1use anyhow::Error;
2use curl::easy::Easy;
3use std::fmt::{self, Write};
4use std::path::PathBuf;
5
6use super::truncate_with_ellipsis;
7
8pub type CargoResult<T> = anyhow::Result<T>;
9
10pub const DEBUG_HEADERS: &[&str] = &[
13 "x-amz-cf-id",
16 "x-amz-cf-pop",
20 "x-amz-request-id",
22 "x-amz-id-2",
24 "x-cache",
26 "x-served-by",
28];
29
30#[derive(Debug)]
31pub struct HttpNotSuccessful {
32 pub code: u32,
33 pub url: String,
34 pub ip: Option<String>,
35 pub body: Vec<u8>,
36 pub headers: Vec<String>,
37}
38
39impl HttpNotSuccessful {
40 pub fn new_from_handle(
41 handle: &mut Easy,
42 initial_url: &str,
43 body: Vec<u8>,
44 headers: Vec<String>,
45 ) -> HttpNotSuccessful {
46 let ip = handle.primary_ip().ok().flatten().map(|s| s.to_string());
47 let url = handle
48 .effective_url()
49 .ok()
50 .flatten()
51 .unwrap_or(initial_url)
52 .to_string();
53 HttpNotSuccessful {
54 code: handle.response_code().unwrap_or(0),
55 url,
56 ip,
57 body,
58 headers,
59 }
60 }
61
62 pub fn display_short(&self) -> String {
64 self.render(false)
65 }
66
67 fn render(&self, show_headers: bool) -> String {
68 let mut result = String::new();
69 let body = std::str::from_utf8(&self.body)
70 .map(|s| truncate_with_ellipsis(s, 512))
71 .unwrap_or_else(|_| format!("[{} non-utf8 bytes]", self.body.len()));
72
73 write!(
74 result,
75 "failed to get successful HTTP response from `{}`",
76 self.url
77 )
78 .unwrap();
79 if let Some(ip) = &self.ip {
80 write!(result, " ({ip})").unwrap();
81 }
82 write!(result, ", got {}\n", self.code).unwrap();
83 if show_headers {
84 let headers: Vec<_> = self
85 .headers
86 .iter()
87 .filter(|header| {
88 let Some((name, _)) = header.split_once(":") else {
89 return false;
90 };
91 DEBUG_HEADERS.contains(&name.to_ascii_lowercase().trim())
92 })
93 .collect();
94 if !headers.is_empty() {
95 writeln!(result, "debug headers:").unwrap();
96 for header in headers {
97 writeln!(result, "{header}").unwrap();
98 }
99 }
100 }
101 write!(result, "body:\n{body}").unwrap();
102 result
103 }
104}
105
106impl fmt::Display for HttpNotSuccessful {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 f.write_str(&self.render(true))
109 }
110}
111
112impl std::error::Error for HttpNotSuccessful {}
113
114pub struct VerboseError {
124 inner: Error,
125}
126
127impl VerboseError {
128 pub fn new(inner: Error) -> VerboseError {
129 VerboseError { inner }
130 }
131}
132
133impl std::error::Error for VerboseError {
134 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
135 self.inner.source()
136 }
137}
138
139impl fmt::Debug for VerboseError {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 self.inner.fmt(f)
142 }
143}
144
145impl fmt::Display for VerboseError {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 self.inner.fmt(f)
148 }
149}
150
151pub struct InternalError {
159 inner: Error,
160}
161
162impl InternalError {
163 pub fn new(inner: Error) -> InternalError {
164 InternalError { inner }
165 }
166}
167
168impl std::error::Error for InternalError {
169 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
170 self.inner.source()
171 }
172}
173
174impl fmt::Debug for InternalError {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 self.inner.fmt(f)
177 }
178}
179
180impl fmt::Display for InternalError {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 self.inner.fmt(f)
183 }
184}
185
186pub struct AlreadyPrintedError {
192 inner: Error,
193}
194
195impl AlreadyPrintedError {
196 pub fn new(inner: Error) -> Self {
197 AlreadyPrintedError { inner }
198 }
199}
200
201impl std::error::Error for AlreadyPrintedError {
202 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
203 self.inner.source()
204 }
205}
206
207impl fmt::Debug for AlreadyPrintedError {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 self.inner.fmt(f)
210 }
211}
212
213impl fmt::Display for AlreadyPrintedError {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 self.inner.fmt(f)
216 }
217}
218
219pub struct ManifestError {
226 cause: Error,
227 manifest: PathBuf,
228}
229
230impl ManifestError {
231 pub fn new<E: Into<Error>>(cause: E, manifest: PathBuf) -> Self {
232 Self {
233 cause: cause.into(),
234 manifest,
235 }
236 }
237
238 pub fn manifest_path(&self) -> &PathBuf {
239 &self.manifest
240 }
241
242 pub fn manifest_causes(&self) -> ManifestCauses<'_> {
246 ManifestCauses { current: self }
247 }
248}
249
250impl std::error::Error for ManifestError {
251 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
252 self.cause.source()
253 }
254}
255
256impl fmt::Debug for ManifestError {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 self.cause.fmt(f)
259 }
260}
261
262impl fmt::Display for ManifestError {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 self.cause.fmt(f)
265 }
266}
267
268pub struct ManifestCauses<'a> {
270 current: &'a ManifestError,
271}
272
273impl<'a> Iterator for ManifestCauses<'a> {
274 type Item = &'a ManifestError;
275
276 fn next(&mut self) -> Option<Self::Item> {
277 self.current = self.current.cause.downcast_ref()?;
278 Some(self.current)
279 }
280}
281
282impl<'a> ::std::iter::FusedIterator for ManifestCauses<'a> {}
283
284pub type CliResult = Result<(), CliError>;
288
289#[derive(Debug)]
290pub struct CliError {
296 pub error: Option<anyhow::Error>,
302 pub exit_code: i32,
304}
305
306impl CliError {
307 pub fn new(error: anyhow::Error, code: i32) -> CliError {
308 CliError {
309 error: Some(error),
310 exit_code: code,
311 }
312 }
313
314 pub fn code(code: i32) -> CliError {
315 CliError {
316 error: None,
317 exit_code: code,
318 }
319 }
320}
321
322impl From<anyhow::Error> for CliError {
323 fn from(err: anyhow::Error) -> CliError {
324 CliError::new(err, 101)
325 }
326}
327
328impl From<clap::Error> for CliError {
329 fn from(err: clap::Error) -> CliError {
330 let code = if err.use_stderr() { 1 } else { 0 };
331 CliError::new(err.into(), code)
332 }
333}
334
335impl From<std::io::Error> for CliError {
336 fn from(err: std::io::Error) -> CliError {
337 CliError::new(err.into(), 1)
338 }
339}
340
341pub fn internal<S: fmt::Display>(error: S) -> anyhow::Error {
345 InternalError::new(anyhow::format_err!("{}", error)).into()
346}