|
1 | 1 | #![allow(clippy::all)]
|
2 | 2 |
|
3 | 3 | use std::collections::BTreeMap;
|
4 |
| -use std::fmt; |
5 | 4 | use std::fs::File;
|
6 | 5 | use std::io::prelude::*;
|
7 | 6 | use std::io::{Cursor, SeekFrom};
|
@@ -127,123 +126,63 @@ struct Crates {
|
127 | 126 | }
|
128 | 127 |
|
129 | 128 | /// Error returned when interacting with a registry.
|
130 |
| -#[derive(Debug)] |
| 129 | +#[derive(Debug, thiserror::Error)] |
131 | 130 | pub enum Error {
|
132 | 131 | /// Error from libcurl.
|
133 |
| - Curl(curl::Error), |
| 132 | + #[error(transparent)] |
| 133 | + Curl(#[from] curl::Error), |
134 | 134 |
|
135 | 135 | /// Error from seriailzing the request payload and deserialzing the
|
136 | 136 | /// response body (like response body didn't match expected structure).
|
137 |
| - Json(serde_json::Error), |
| 137 | + #[error(transparent)] |
| 138 | + Json(#[from] serde_json::Error), |
138 | 139 |
|
139 | 140 | /// Error from IO. Mostly from reading the tarball to upload.
|
140 |
| - Io(std::io::Error), |
| 141 | + #[error("failed to seek tarball")] |
| 142 | + Io(#[from] std::io::Error), |
141 | 143 |
|
142 | 144 | /// Response body was not valid utf8.
|
143 |
| - Utf8(std::string::FromUtf8Error), |
| 145 | + #[error("invalid response body from server")] |
| 146 | + Utf8(#[from] std::string::FromUtf8Error), |
144 | 147 |
|
145 | 148 | /// Error from API response containing JSON field `errors.details`.
|
| 149 | + #[error( |
| 150 | + "the remote server responded with an error{}: {}", |
| 151 | + status(*code), |
| 152 | + errors.join(", "), |
| 153 | + )] |
146 | 154 | Api {
|
147 | 155 | code: u32,
|
148 | 156 | headers: Vec<String>,
|
149 | 157 | errors: Vec<String>,
|
150 | 158 | },
|
151 | 159 |
|
152 | 160 | /// Error from API response which didn't have pre-programmed `errors.details`.
|
| 161 | + #[error( |
| 162 | + "failed to get a 200 OK response, got {code}\nheaders:\n\t{}\nbody:\n{body}", |
| 163 | + headers.join("\n\t"), |
| 164 | + )] |
153 | 165 | Code {
|
154 | 166 | code: u32,
|
155 | 167 | headers: Vec<String>,
|
156 | 168 | body: String,
|
157 | 169 | },
|
158 | 170 |
|
159 | 171 | /// Reason why the token was invalid.
|
| 172 | + #[error("{0}")] |
160 | 173 | InvalidToken(&'static str),
|
161 | 174 |
|
162 | 175 | /// Server was unavailable and timeouted. Happened when uploading a way
|
163 | 176 | /// too large tarball to crates.io.
|
| 177 | + #[error( |
| 178 | + "Request timed out after 30 seconds. If you're trying to \ |
| 179 | + upload a crate it may be too large. If the crate is under \ |
| 180 | + 10MB in size, you can email help@crates.io for assistance.\n\ |
| 181 | + Total size was {0}." |
| 182 | + )] |
164 | 183 | Timeout(u64),
|
165 | 184 | }
|
166 | 185 |
|
167 |
| -impl std::error::Error for Error { |
168 |
| - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
169 |
| - match self { |
170 |
| - Self::Curl(e) => Some(e), |
171 |
| - Self::Json(e) => Some(e), |
172 |
| - Self::Io(e) => Some(e), |
173 |
| - Self::Utf8(e) => Some(e), |
174 |
| - Self::Api { .. } => None, |
175 |
| - Self::Code { .. } => None, |
176 |
| - Self::InvalidToken(..) => None, |
177 |
| - Self::Timeout(..) => None, |
178 |
| - } |
179 |
| - } |
180 |
| -} |
181 |
| - |
182 |
| -impl fmt::Display for Error { |
183 |
| - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
184 |
| - match self { |
185 |
| - Self::Curl(e) => write!(f, "{e}"), |
186 |
| - Self::Json(e) => write!(f, "{e}"), |
187 |
| - Self::Io(e) => write!(f, "{e}"), |
188 |
| - Self::Utf8(e) => write!(f, "{e}"), |
189 |
| - Self::Api { code, errors, .. } => { |
190 |
| - f.write_str("the remote server responded with an error")?; |
191 |
| - if *code != 200 { |
192 |
| - write!(f, " (status {} {})", code, reason(*code))?; |
193 |
| - }; |
194 |
| - write!(f, ": {}", errors.join(", ")) |
195 |
| - } |
196 |
| - Self::Code { |
197 |
| - code, |
198 |
| - headers, |
199 |
| - body, |
200 |
| - } => write!( |
201 |
| - f, |
202 |
| - "failed to get a 200 OK response, got {}\n\ |
203 |
| - headers:\n\ |
204 |
| - \t{}\n\ |
205 |
| - body:\n\ |
206 |
| - {}", |
207 |
| - code, |
208 |
| - headers.join("\n\t"), |
209 |
| - body |
210 |
| - ), |
211 |
| - Self::InvalidToken(e) => write!(f, "{e}"), |
212 |
| - Self::Timeout(tarball_size) => write!( |
213 |
| - f, |
214 |
| - "Request timed out after 30 seconds. If you're trying to \ |
215 |
| - upload a crate it may be too large. If the crate is under \ |
216 |
| - 10MB in size, you can email help@crates.io for assistance.\n\ |
217 |
| - Total size was {tarball_size}." |
218 |
| - ), |
219 |
| - } |
220 |
| - } |
221 |
| -} |
222 |
| - |
223 |
| -impl From<curl::Error> for Error { |
224 |
| - fn from(error: curl::Error) -> Self { |
225 |
| - Self::Curl(error) |
226 |
| - } |
227 |
| -} |
228 |
| - |
229 |
| -impl From<serde_json::Error> for Error { |
230 |
| - fn from(error: serde_json::Error) -> Self { |
231 |
| - Self::Json(error) |
232 |
| - } |
233 |
| -} |
234 |
| - |
235 |
| -impl From<std::io::Error> for Error { |
236 |
| - fn from(error: std::io::Error) -> Self { |
237 |
| - Self::Io(error) |
238 |
| - } |
239 |
| -} |
240 |
| - |
241 |
| -impl From<std::string::FromUtf8Error> for Error { |
242 |
| - fn from(error: std::string::FromUtf8Error) -> Self { |
243 |
| - Self::Utf8(error) |
244 |
| - } |
245 |
| -} |
246 |
| - |
247 | 186 | impl Registry {
|
248 | 187 | /// Creates a new `Registry`.
|
249 | 188 | ///
|
@@ -500,6 +439,15 @@ impl Registry {
|
500 | 439 | }
|
501 | 440 | }
|
502 | 441 |
|
| 442 | +fn status(code: u32) -> String { |
| 443 | + if code == 200 { |
| 444 | + String::new() |
| 445 | + } else { |
| 446 | + let reason = reason(code); |
| 447 | + format!(" (status {code} {reason})") |
| 448 | + } |
| 449 | +} |
| 450 | + |
503 | 451 | fn reason(code: u32) -> &'static str {
|
504 | 452 | // Taken from https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
505 | 453 | match code {
|
|
0 commit comments