Skip to content

Commit 966a89b

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 d8c05d7 commit 966a89b

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
@@ -17,4 +17,5 @@ curl.workspace = true
1717
percent-encoding.workspace = true
1818
serde = { workspace = true, features = ["derive"] }
1919
serde_json.workspace = true
20+
thiserror.workspace = true
2021
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};
@@ -127,123 +126,63 @@ struct Crates {
127126
}
128127

129128
/// Error returned when interacting with a registry.
130-
#[derive(Debug)]
129+
#[derive(Debug, thiserror::Error)]
131130
pub enum Error {
132131
/// Error from libcurl.
133-
Curl(curl::Error),
132+
#[error(transparent)]
133+
Curl(#[from] curl::Error),
134134

135135
/// Error from seriailzing the request payload and deserialzing the
136136
/// response body (like response body didn't match expected structure).
137-
Json(serde_json::Error),
137+
#[error(transparent)]
138+
Json(#[from] serde_json::Error),
138139

139140
/// 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),
141143

142144
/// Response body was not valid utf8.
143-
Utf8(std::string::FromUtf8Error),
145+
#[error("invalid response body from server")]
146+
Utf8(#[from] std::string::FromUtf8Error),
144147

145148
/// 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+
)]
146154
Api {
147155
code: u32,
148156
headers: Vec<String>,
149157
errors: Vec<String>,
150158
},
151159

152160
/// 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+
)]
153165
Code {
154166
code: u32,
155167
headers: Vec<String>,
156168
body: String,
157169
},
158170

159171
/// Reason why the token was invalid.
172+
#[error("{0}")]
160173
InvalidToken(&'static str),
161174

162175
/// Server was unavailable and timeouted. Happened when uploading a way
163176
/// 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+
)]
164183
Timeout(u64),
165184
}
166185

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-
247186
impl Registry {
248187
/// Creates a new `Registry`.
249188
///
@@ -500,6 +439,15 @@ impl Registry {
500439
}
501440
}
502441

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