|
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};
|
@@ -140,123 +139,63 @@ struct Crates {
|
140 | 139 | }
|
141 | 140 |
|
142 | 141 | /// Error returned when interacting with a registry.
|
143 |
| -#[derive(Debug)] |
| 142 | +#[derive(Debug, thiserror::Error)] |
144 | 143 | pub enum Error {
|
145 | 144 | /// Error from libcurl.
|
146 |
| - Curl(curl::Error), |
| 145 | + #[error(transparent)] |
| 146 | + Curl(#[from] curl::Error), |
147 | 147 |
|
148 | 148 | /// Error from seriailzing the request payload and deserialzing the
|
149 | 149 | /// response body (like response body didn't match expected structure).
|
150 |
| - Json(serde_json::Error), |
| 150 | + #[error(transparent)] |
| 151 | + Json(#[from] serde_json::Error), |
151 | 152 |
|
152 | 153 | /// Error from IO. Mostly from reading the tarball to upload.
|
153 |
| - Io(std::io::Error), |
| 154 | + #[error("failed to seek tarball")] |
| 155 | + Io(#[from] std::io::Error), |
154 | 156 |
|
155 | 157 | /// Response body was not valid utf8.
|
156 |
| - Utf8(std::string::FromUtf8Error), |
| 158 | + #[error("invalid response body from server")] |
| 159 | + Utf8(#[from] std::string::FromUtf8Error), |
157 | 160 |
|
158 | 161 | /// Error from API response containing JSON field `errors.details`.
|
| 162 | + #[error( |
| 163 | + "the remote server responded with an error{}: {}", |
| 164 | + status(*code), |
| 165 | + errors.join(", "), |
| 166 | + )] |
159 | 167 | Api {
|
160 | 168 | code: u32,
|
161 | 169 | errors: Vec<String>,
|
162 | 170 | challenge: Option<Challenge>,
|
163 | 171 | },
|
164 | 172 |
|
165 | 173 | /// Error from API response which didn't have pre-programmed `errors.details`.
|
| 174 | + #[error( |
| 175 | + "failed to get a 200 OK response, got {code}\nheaders:\n\t{}\nbody:\n{body}", |
| 176 | + headers.join("\n\t"), |
| 177 | + )] |
166 | 178 | Code {
|
167 | 179 | code: u32,
|
168 | 180 | headers: Vec<String>,
|
169 | 181 | body: String,
|
170 | 182 | },
|
171 | 183 |
|
172 | 184 | /// Reason why the token was invalid.
|
| 185 | + #[error("{0}")] |
173 | 186 | InvalidToken(&'static str),
|
174 | 187 |
|
175 | 188 | /// Server was unavailable and timeouted. Happened when uploading a way
|
176 | 189 | /// too large tarball to crates.io.
|
| 190 | + #[error( |
| 191 | + "Request timed out after 30 seconds. If you're trying to \ |
| 192 | + upload a crate it may be too large. If the crate is under \ |
| 193 | + 10MB in size, you can email help@crates.io for assistance.\n\ |
| 194 | + Total size was {0}." |
| 195 | + )] |
177 | 196 | Timeout(u64),
|
178 | 197 | }
|
179 | 198 |
|
180 |
| -impl std::error::Error for Error { |
181 |
| - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
182 |
| - match self { |
183 |
| - Self::Curl(e) => Some(e), |
184 |
| - Self::Json(e) => Some(e), |
185 |
| - Self::Io(e) => Some(e), |
186 |
| - Self::Utf8(e) => Some(e), |
187 |
| - Self::Api { .. } => None, |
188 |
| - Self::Code { .. } => None, |
189 |
| - Self::InvalidToken(..) => None, |
190 |
| - Self::Timeout(..) => None, |
191 |
| - } |
192 |
| - } |
193 |
| -} |
194 |
| - |
195 |
| -impl fmt::Display for Error { |
196 |
| - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
197 |
| - match self { |
198 |
| - Self::Curl(e) => write!(f, "{e}"), |
199 |
| - Self::Json(e) => write!(f, "{e}"), |
200 |
| - Self::Io(e) => write!(f, "{e}"), |
201 |
| - Self::Utf8(e) => write!(f, "{e}"), |
202 |
| - Self::Api { code, errors, .. } => { |
203 |
| - f.write_str("the remote server responded with an error")?; |
204 |
| - if *code != 200 { |
205 |
| - write!(f, " (status {} {})", code, reason(*code))?; |
206 |
| - }; |
207 |
| - write!(f, ": {}", errors.join(", ")) |
208 |
| - } |
209 |
| - Self::Code { |
210 |
| - code, |
211 |
| - headers, |
212 |
| - body, |
213 |
| - } => write!( |
214 |
| - f, |
215 |
| - "failed to get a 200 OK response, got {}\n\ |
216 |
| - headers:\n\ |
217 |
| - \t{}\n\ |
218 |
| - body:\n\ |
219 |
| - {}", |
220 |
| - code, |
221 |
| - headers.join("\n\t"), |
222 |
| - body |
223 |
| - ), |
224 |
| - Self::InvalidToken(e) => write!(f, "{e}"), |
225 |
| - Self::Timeout(tarball_size) => write!( |
226 |
| - f, |
227 |
| - "Request timed out after 30 seconds. If you're trying to \ |
228 |
| - upload a crate it may be too large. If the crate is under \ |
229 |
| - 10MB in size, you can email help@crates.io for assistance.\n\ |
230 |
| - Total size was {tarball_size}." |
231 |
| - ), |
232 |
| - } |
233 |
| - } |
234 |
| -} |
235 |
| - |
236 |
| -impl From<curl::Error> for Error { |
237 |
| - fn from(error: curl::Error) -> Self { |
238 |
| - Self::Curl(error) |
239 |
| - } |
240 |
| -} |
241 |
| - |
242 |
| -impl From<serde_json::Error> for Error { |
243 |
| - fn from(error: serde_json::Error) -> Self { |
244 |
| - Self::Json(error) |
245 |
| - } |
246 |
| -} |
247 |
| - |
248 |
| -impl From<std::io::Error> for Error { |
249 |
| - fn from(error: std::io::Error) -> Self { |
250 |
| - Self::Io(error) |
251 |
| - } |
252 |
| -} |
253 |
| - |
254 |
| -impl From<std::string::FromUtf8Error> for Error { |
255 |
| - fn from(error: std::string::FromUtf8Error) -> Self { |
256 |
| - Self::Utf8(error) |
257 |
| - } |
258 |
| -} |
259 |
| - |
260 | 199 | impl Registry {
|
261 | 200 | /// Creates a new `Registry`.
|
262 | 201 | ///
|
@@ -610,6 +549,15 @@ impl Challenge {
|
610 | 549 | }
|
611 | 550 | }
|
612 | 551 |
|
| 552 | +fn status(code: u32) -> String { |
| 553 | + if code == 200 { |
| 554 | + String::new() |
| 555 | + } else { |
| 556 | + let reason = reason(code); |
| 557 | + format!(" (status {code} {reason})") |
| 558 | + } |
| 559 | +} |
| 560 | + |
613 | 561 | fn reason(code: u32) -> &'static str {
|
614 | 562 | // Taken from https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
615 | 563 | match code {
|
|
0 commit comments