Skip to content

Commit def249f

Browse files
committed
Fixes review comments
Fix some formatting items. Changes Internal error kind to preserve the original error. Changes network retry logic to inspect full error chain for spurious errors.
1 parent 68f5584 commit def249f

File tree

8 files changed

+69
-32
lines changed

8 files changed

+69
-32
lines changed

src/bin/cargo.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[String]) -> C
332332
Err(e) => e,
333333
};
334334

335-
if let CargoError(CargoErrorKind::ProcessErrorKind(ref perr), ..) = err {
335+
if let &CargoErrorKind::ProcessErrorKind(ref perr) = err.kind() {
336336
if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) {
337337
return Err(CliError::code(code));
338338
}

src/cargo/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ extern crate url;
3333
use std::io;
3434
use std::fmt;
3535
use std::error::Error;
36+
3637
use error_chain::ChainedError;
3738
use rustc_serialize::Decodable;
3839
use serde::ser;

src/cargo/ops/cargo_rustc/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ fn rustc(cx: &mut Context, unit: &Unit, exec: Arc<Executor>) -> CargoResult<Work
372372
format!("Could not compile `{}`.", name)
373373
})?;
374374
} else {
375-
exec.exec(rustc, &package_id).map_err(|e| e.to_internal()).chain_err(|| {
375+
exec.exec(rustc, &package_id).map_err(|e| e.into_internal()).chain_err(|| {
376376
format!("Could not compile `{}`.", name)
377377
})?;
378378
}

src/cargo/sources/directory.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,7 @@ impl<'cfg> Source for DirectorySource<'cfg> {
120120
pkg.package_id().version())
121121

122122
})?;
123-
let cksum: Checksum = serde_json::from_str(&cksum)
124-
.chain_err(|| {
123+
let cksum: Checksum = serde_json::from_str(&cksum).chain_err(|| {
125124
format!("failed to decode `.cargo-checksum.json` of \
126125
{} v{}",
127126
pkg.package_id().name(),

src/cargo/sources/git/source.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl<'cfg> Source for GitSource<'cfg> {
148148
trace!("updating git source `{:?}`", self.remote);
149149

150150
let repo = self.remote.checkout(&db_path, self.config)?;
151-
let rev = repo.rev_for(&self.reference).map_err(CargoError::to_internal)?;
151+
let rev = repo.rev_for(&self.reference).map_err(CargoError::into_internal)?;
152152
(repo, rev)
153153
} else {
154154
(self.remote.db_at(&db_path)?, actual_rev.unwrap())

src/cargo/sources/git/utils.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ impl<'a> GitCheckout<'a> {
297297

298298
for mut child in repo.submodules()?.into_iter() {
299299
update_submodule(repo, &mut child, cargo_config)
300-
.map_err(CargoError::to_internal)
300+
.map_err(CargoError::into_internal)
301301
.chain_err(|| {
302302
format!("failed to update submodule `{}`",
303303
child.name().unwrap_or(""))
@@ -532,7 +532,7 @@ fn with_authentication<T, F>(url: &str, cfg: &git2::Config, mut f: F)
532532
// In the case of an authentication failure (where we tried something) then
533533
// we try to give a more helpful error message about precisely what we
534534
// tried.
535-
res.map_err(CargoError::from).map_err(|e| e.to_internal()).chain_err(|| {
535+
res.map_err(CargoError::from).map_err(|e| e.into_internal()).chain_err(|| {
536536
let mut msg = "failed to authenticate when downloading \
537537
repository".to_string();
538538
if !ssh_agent_attempts.is_empty() {

src/cargo/util/errors.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ error_chain! {
4141
}
4242

4343
errors {
44-
Internal(description: String){
45-
description(&description)
46-
display("{}", &description)
44+
Internal(err: Box<CargoErrorKind>) {
45+
description(err.description())
46+
display("{}", *err)
4747
}
4848
ProcessErrorKind(proc_err: ProcessError) {
4949
description(&proc_err.desc)
@@ -61,9 +61,8 @@ error_chain! {
6161
}
6262

6363
impl CargoError {
64-
pub fn to_internal(self) -> Self {
65-
//This is actually bad, because it loses the cause information for foreign_link
66-
CargoError(CargoErrorKind::Internal(self.description().to_string()), self.1)
64+
pub fn into_internal(self) -> Self {
65+
CargoError(CargoErrorKind::Internal(Box::new(self.0)), self.1)
6766
}
6867

6968
fn is_human(&self) -> bool {
@@ -282,5 +281,5 @@ pub fn internal<S: fmt::Display>(error: S) -> CargoError {
282281
}
283282

284283
fn _internal(error: &fmt::Display) -> CargoError {
285-
CargoErrorKind::Internal(error.to_string()).into()
284+
CargoError::from_kind(error.to_string().into()).into_internal()
286285
}

src/cargo/util/network.rs

+56-18
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,53 @@
1+
use std;
2+
use std::error::Error;
3+
4+
use error_chain::ChainedError;
5+
16
use util::Config;
27
use util::errors::{CargoError, CargoErrorKind, CargoResult};
38

49
use git2;
10+
fn maybe_spurious<E, EKind>(err: &E) -> bool
11+
where E: ChainedError<ErrorKind=EKind> + 'static {
12+
//Error inspection in non-verbose mode requires inspecting the
13+
//error kind to avoid printing Internal errors. The downcasting
14+
//machinery requires &(Error + 'static), but the iterator (and
15+
//underlying `cause`) return &Error. Because the borrows are
16+
//constrained to this handling method, and because the original
17+
//error object is constrained to be 'static, we're casting away
18+
//the borrow's actual lifetime for purposes of downcasting and
19+
//inspecting the error chain
20+
unsafe fn extend_lifetime(r: &Error) -> &(Error + 'static) {
21+
std::mem::transmute::<&Error, &Error>(r)
22+
}
523

6-
fn maybe_spurious(err: &CargoError) -> bool {
7-
match err.kind() {
8-
&CargoErrorKind::Git(ref git_err) => {
9-
match git_err.class() {
10-
git2::ErrorClass::Net |
11-
git2::ErrorClass::Os => true,
12-
_ => false
24+
for e in err.iter() {
25+
let e = unsafe { extend_lifetime(e) };
26+
if let Some(cargo_err) = e.downcast_ref::<CargoError>() {
27+
match cargo_err.kind() {
28+
&CargoErrorKind::Git(ref git_err) => {
29+
match git_err.class() {
30+
git2::ErrorClass::Net |
31+
git2::ErrorClass::Os => return true,
32+
_ => ()
33+
}
1334
}
35+
&CargoErrorKind::Curl(ref curl_err)
36+
if curl_err.is_couldnt_connect() ||
37+
curl_err.is_couldnt_resolve_proxy() ||
38+
curl_err.is_couldnt_resolve_host() ||
39+
curl_err.is_operation_timedout() ||
40+
curl_err.is_recv_error() => {
41+
return true
42+
}
43+
&CargoErrorKind::HttpNot200(code, ref _url) if 500 <= code && code < 600 => {
44+
return true
45+
}
46+
_ => ()
1447
}
15-
&CargoErrorKind::Curl(ref curl_err) => {
16-
curl_err.is_couldnt_connect() ||
17-
curl_err.is_couldnt_resolve_proxy() ||
18-
curl_err.is_couldnt_resolve_host() ||
19-
curl_err.is_operation_timedout() ||
20-
curl_err.is_recv_error()
21-
}
22-
&CargoErrorKind::HttpNot200(code, ref _url) => {
23-
500 <= code && code < 600
24-
}
25-
_ => false
48+
}
2649
}
50+
false
2751
}
2852

2953
/// Wrapper method for network call retry logic.
@@ -67,3 +91,17 @@ fn with_retry_repeats_the_call_then_works() {
6791
let result = with_retry(&config, || results.pop().unwrap());
6892
assert_eq!(result.unwrap(), ())
6993
}
94+
95+
#[test]
96+
fn with_retry_finds_nested_spurious_errors() {
97+
//Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
98+
//String error messages are not considered spurious
99+
let error1 : CargoError = CargoErrorKind::HttpNot200(501, "Uri".to_string()).into();
100+
let error1 = CargoError::with_chain(error1, "A non-spurious wrapping err");
101+
let error2 = CargoError::from_kind(CargoErrorKind::HttpNot200(502, "Uri".to_string()));
102+
let error2 = CargoError::with_chain(error2, "A second chained error");
103+
let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
104+
let config = Config::default().unwrap();
105+
let result = with_retry(&config, || results.pop().unwrap());
106+
assert_eq!(result.unwrap(), ())
107+
}

0 commit comments

Comments
 (0)