Skip to content

Commit 53521cd

Browse files
committed
refactor(crates-io): use thiserror
Optionally use `thiserror` to reduce boilerplates but this part can be dropped if we don't want.
1 parent d99f4c1 commit 53521cd

File tree

5 files changed

+39
-88
lines changed

5 files changed

+39
-88
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ syn = { version = "2.0.14", features = ["extra-traits", "full"] }
8383
tar = { version = "0.4.38", default-features = false }
8484
tempfile = "3.1.0"
8585
termcolor = "1.1.2"
86+
thiserror = "1.0.40"
8687
time = { version = "0.3", features = ["parsing", "formatting"] }
8788
toml = "0.7.0"
8889
toml_edit = "0.19.0"

crates/crates-io/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ log.workspace = true
1919
percent-encoding.workspace = true
2020
serde = { workspace = true, features = ["derive"] }
2121
serde_json.workspace = true
22+
thiserror.workspace = true
2223
url.workspace = true

crates/crates-io/lib.rs

+34-86
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#![allow(clippy::all)]
22

33
use std::collections::BTreeMap;
4-
use std::fmt;
54
use std::fs::File;
65
use std::io::prelude::*;
76
use std::io::{Cursor, SeekFrom};
@@ -140,123 +139,63 @@ struct Crates {
140139
}
141140

142141
/// Error returned when interacting with a registry.
143-
#[derive(Debug)]
142+
#[derive(Debug, thiserror::Error)]
144143
pub enum Error {
145144
/// Error from libcurl.
146-
Curl(curl::Error),
145+
#[error(transparent)]
146+
Curl(#[from] curl::Error),
147147

148148
/// Error from seriailzing the request payload and deserialzing the
149149
/// response body (like response body didn't match expected structure).
150-
Json(serde_json::Error),
150+
#[error(transparent)]
151+
Json(#[from] serde_json::Error),
151152

152153
/// 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),
154156

155157
/// Response body was not valid utf8.
156-
Utf8(std::string::FromUtf8Error),
158+
#[error("invalid response body from server")]
159+
Utf8(#[from] std::string::FromUtf8Error),
157160

158161
/// 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+
)]
159167
Api {
160168
code: u32,
161169
errors: Vec<String>,
162170
challenge: Option<Challenge>,
163171
},
164172

165173
/// 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+
)]
166178
Code {
167179
code: u32,
168180
headers: Vec<String>,
169181
body: String,
170182
},
171183

172184
/// Reason why the token was invalid.
185+
#[error("{0}")]
173186
InvalidToken(&'static str),
174187

175188
/// Server was unavailable and timeouted. Happened when uploading a way
176189
/// 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+
)]
177196
Timeout(u64),
178197
}
179198

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-
260199
impl Registry {
261200
/// Creates a new `Registry`.
262201
///
@@ -610,6 +549,15 @@ impl Challenge {
610549
}
611550
}
612551

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+
613561
fn reason(code: u32) -> &'static str {
614562
// Taken from https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
615563
match code {

tests/testsuite/publish.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2023,10 +2023,10 @@ fn api_other_error() {
20232023
[ERROR] failed to publish to registry at http://127.0.0.1:[..]/
20242024
20252025
Caused by:
2026-
invalid response from server
2026+
invalid response body from server
20272027
20282028
Caused by:
2029-
response body was not valid utf-8
2029+
invalid utf-8 sequence of [..]
20302030
",
20312031
)
20322032
.run();

0 commit comments

Comments
 (0)