Skip to content

Commit 2090965

Browse files
committed
Add PackageError wrappers for activation errors
1 parent 571a542 commit 2090965

File tree

3 files changed

+100
-9
lines changed

3 files changed

+100
-9
lines changed

src/cargo/core/resolver/mod.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ use core::interning::InternedString;
5858
use core::PackageIdSpec;
5959
use core::{Dependency, PackageId, Registry, Summary};
6060
use util::config::Config;
61-
use util::errors::{CargoError, CargoResult};
61+
use util::errors::{CargoResult, PackageError};
6262
use util::lev_distance::lev_distance;
6363
use util::profile;
6464

@@ -825,7 +825,9 @@ fn activation_error(
825825
conflicting_activations: &HashMap<PackageId, ConflictReason>,
826826
candidates: &[Candidate],
827827
config: Option<&Config>,
828-
) -> CargoError {
828+
) -> PackageError {
829+
let to_package_err = |err| PackageError::new(err, parent.package_id().clone());
830+
829831
let graph = cx.graph();
830832
if !candidates.is_empty() {
831833
let mut msg = format!("failed to select a version for `{}`.", dep.package_name());
@@ -899,7 +901,7 @@ fn activation_error(
899901
msg.push_str(&*dep.package_name());
900902
msg.push_str("` which could resolve this conflict");
901903

902-
return format_err!("{}", msg);
904+
return to_package_err(format_err!("{}", msg));
903905
}
904906

905907
// We didn't actually find any candidates, so we need to
@@ -913,7 +915,7 @@ fn activation_error(
913915
new_dep.set_version_req(all_req);
914916
let mut candidates = match registry.query_vec(&new_dep, false) {
915917
Ok(candidates) => candidates,
916-
Err(e) => return e,
918+
Err(e) => return to_package_err(e),
917919
};
918920
candidates.sort_unstable_by(|a, b| b.version().cmp(a.version()));
919921

@@ -964,7 +966,7 @@ fn activation_error(
964966
// was meant. So we try asking the registry for a `fuzzy` search for suggestions.
965967
let mut candidates = Vec::new();
966968
if let Err(e) = registry.query(&new_dep, &mut |s| candidates.push(s.name()), true) {
967-
return e;
969+
return to_package_err(e);
968970
};
969971
candidates.sort_unstable();
970972
candidates.dedup();
@@ -1012,7 +1014,7 @@ fn activation_error(
10121014
}
10131015
}
10141016

1015-
format_err!("{}", msg)
1017+
to_package_err(format_err!("{}", msg))
10161018
}
10171019

10181020
/// Returns String representation of dependency chain for a particular `pkgid`.

src/cargo/util/errors.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::process::{ExitStatus, Output};
55
use std::str;
66
use std::path::PathBuf;
77

8-
use core::{TargetKind, Workspace};
8+
use core::{TargetKind, Workspace, PackageId};
99
use failure::{Context, Error, Fail};
1010
use clap;
1111

@@ -135,6 +135,45 @@ impl<'a> Iterator for ManifestCauses<'a> {
135135

136136
impl<'a> ::std::iter::FusedIterator for ManifestCauses<'a> {}
137137

138+
/// Error wrapper related to a particular package and providing it's `PackageId`.
139+
///
140+
/// This error adds no displayable info of it's own.
141+
pub struct PackageError {
142+
cause: Error,
143+
package: PackageId,
144+
}
145+
146+
impl PackageError {
147+
pub fn new<E: Into<Error>>(cause: E, package: PackageId) -> Self {
148+
Self {
149+
cause: cause.into(),
150+
package,
151+
}
152+
}
153+
154+
pub fn package_id(&self) -> &PackageId {
155+
&self.package
156+
}
157+
}
158+
159+
impl Fail for PackageError {
160+
fn cause(&self) -> Option<&Fail> {
161+
self.cause.as_fail().cause()
162+
}
163+
}
164+
165+
impl fmt::Debug for PackageError {
166+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167+
self.cause.fmt(f)
168+
}
169+
}
170+
171+
impl fmt::Display for PackageError {
172+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173+
self.cause.fmt(f)
174+
}
175+
}
176+
138177
// =============================================================================
139178
// Process errors
140179
#[derive(Debug, Fail)]

tests/testsuite/member_errors.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
use cargo::core::Workspace;
2-
use cargo::util::{config::Config, errors::ManifestError};
1+
use cargo::core::{compiler::CompileMode, Workspace};
2+
use cargo::ops::{self, CompileOptions};
3+
use cargo::util::{
4+
config::Config,
5+
errors::{ManifestError, PackageError},
6+
};
37

48
use support::project;
59

@@ -102,3 +106,49 @@ fn member_manifest_path_io_error() {
102106
assert_eq!(causes[0].manifest_path(), &member_manifest_path);
103107
assert_eq!(causes[1].manifest_path(), &missing_manifest_path);
104108
}
109+
110+
/// Test dependency version errors provide which package failed via a `PackageError`.
111+
#[test]
112+
fn member_manifest_version_error() {
113+
let p = project()
114+
.file(
115+
"Cargo.toml",
116+
r#"
117+
[project]
118+
name = "foo"
119+
version = "0.1.0"
120+
authors = []
121+
122+
[dependencies]
123+
bar = { path = "bar" }
124+
125+
[workspace]
126+
"#,
127+
)
128+
.file("src/main.rs", "fn main() {}")
129+
.file(
130+
"bar/Cargo.toml",
131+
r#"
132+
[project]
133+
name = "bar"
134+
version = "0.1.0"
135+
authors = []
136+
137+
[dependencies]
138+
i-dont-exist = "0.55"
139+
"#,
140+
)
141+
.file("bar/src/main.rs", "fn main() {}")
142+
.build();
143+
144+
let config = Config::default().unwrap();
145+
let ws = Workspace::new(&p.root().join("Cargo.toml"), &config).unwrap();
146+
let compile_options = CompileOptions::new(&config, CompileMode::Build).unwrap();
147+
let member_bar = ws.members().find(|m| &*m.name() == "bar").unwrap();
148+
149+
let error = ops::compile(&ws, &compile_options).map(|_| ()).unwrap_err();
150+
eprintln!("{:?}", error);
151+
152+
let package_err: &PackageError = error.downcast_ref().expect("Not a PackageError");
153+
assert_eq!(package_err.package_id(), member_bar.package_id());
154+
}

0 commit comments

Comments
 (0)