]> git.proxmox.com Git - cargo.git/commitdiff
Add PackageError wrappers for activation errors
authorAlex Butler <alexheretic@gmail.com>
Mon, 15 Oct 2018 18:29:53 +0000 (19:29 +0100)
committerAlex Butler <alexheretic@gmail.com>
Mon, 15 Oct 2018 18:29:53 +0000 (19:29 +0100)
src/cargo/core/resolver/mod.rs
src/cargo/util/errors.rs
tests/testsuite/member_errors.rs

index d1b3fe878cef0d93e04fe1612d69b4eadba65002..4e91e6372b5daad1172235b0487cd594b4ca3a59 100644 (file)
@@ -58,7 +58,7 @@ use core::interning::InternedString;
 use core::PackageIdSpec;
 use core::{Dependency, PackageId, Registry, Summary};
 use util::config::Config;
-use util::errors::{CargoError, CargoResult};
+use util::errors::{CargoResult, PackageError};
 use util::lev_distance::lev_distance;
 use util::profile;
 
@@ -825,7 +825,9 @@ fn activation_error(
     conflicting_activations: &HashMap<PackageId, ConflictReason>,
     candidates: &[Candidate],
     config: Option<&Config>,
-) -> CargoError {
+) -> PackageError {
+    let to_package_err = |err| PackageError::new(err, parent.package_id().clone());
+
     let graph = cx.graph();
     if !candidates.is_empty() {
         let mut msg = format!("failed to select a version for `{}`.", dep.package_name());
@@ -899,7 +901,7 @@ fn activation_error(
         msg.push_str(&*dep.package_name());
         msg.push_str("` which could resolve this conflict");
 
-        return format_err!("{}", msg);
+        return to_package_err(format_err!("{}", msg));
     }
 
     // We didn't actually find any candidates, so we need to
@@ -913,7 +915,7 @@ fn activation_error(
     new_dep.set_version_req(all_req);
     let mut candidates = match registry.query_vec(&new_dep, false) {
         Ok(candidates) => candidates,
-        Err(e) => return e,
+        Err(e) => return to_package_err(e),
     };
     candidates.sort_unstable_by(|a, b| b.version().cmp(a.version()));
 
@@ -964,7 +966,7 @@ fn activation_error(
         // was meant. So we try asking the registry for a `fuzzy` search for suggestions.
         let mut candidates = Vec::new();
         if let Err(e) = registry.query(&new_dep, &mut |s| candidates.push(s.name()), true) {
-            return e;
+            return to_package_err(e);
         };
         candidates.sort_unstable();
         candidates.dedup();
@@ -1012,7 +1014,7 @@ fn activation_error(
         }
     }
 
-    format_err!("{}", msg)
+    to_package_err(format_err!("{}", msg))
 }
 
 /// Returns String representation of dependency chain for a particular `pkgid`.
index 6fc28981ddcaded65360029b18f052df0d6db598..91fa82744d136acd412448fadedd8ac7a1e6b8c6 100644 (file)
@@ -5,7 +5,7 @@ use std::process::{ExitStatus, Output};
 use std::str;
 use std::path::PathBuf;
 
-use core::{TargetKind, Workspace};
+use core::{TargetKind, Workspace, PackageId};
 use failure::{Context, Error, Fail};
 use clap;
 
@@ -135,6 +135,45 @@ impl<'a> Iterator for ManifestCauses<'a> {
 
 impl<'a> ::std::iter::FusedIterator for ManifestCauses<'a> {}
 
+/// Error wrapper related to a particular package and providing it's `PackageId`.
+///
+/// This error adds no displayable info of it's own.
+pub struct PackageError {
+    cause: Error,
+    package: PackageId,
+}
+
+impl PackageError {
+    pub fn new<E: Into<Error>>(cause: E, package: PackageId) -> Self {
+        Self {
+            cause: cause.into(),
+            package,
+        }
+    }
+
+    pub fn package_id(&self) -> &PackageId {
+        &self.package
+    }
+}
+
+impl Fail for PackageError {
+    fn cause(&self) -> Option<&Fail> {
+        self.cause.as_fail().cause()
+    }
+}
+
+impl fmt::Debug for PackageError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.cause.fmt(f)
+    }
+}
+
+impl fmt::Display for PackageError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.cause.fmt(f)
+    }
+}
+
 // =============================================================================
 // Process errors
 #[derive(Debug, Fail)]
index d8458501f457876d10a3332d61cd8aa98a9b4950..f26ce04aa3f105ee1ac53b1bed679d0e1988529d 100644 (file)
@@ -1,5 +1,9 @@
-use cargo::core::Workspace;
-use cargo::util::{config::Config, errors::ManifestError};
+use cargo::core::{compiler::CompileMode, Workspace};
+use cargo::ops::{self, CompileOptions};
+use cargo::util::{
+    config::Config,
+    errors::{ManifestError, PackageError},
+};
 
 use support::project;
 
@@ -102,3 +106,49 @@ fn member_manifest_path_io_error() {
     assert_eq!(causes[0].manifest_path(), &member_manifest_path);
     assert_eq!(causes[1].manifest_path(), &missing_manifest_path);
 }
+
+/// Test dependency version errors provide which package failed via a `PackageError`.
+#[test]
+fn member_manifest_version_error() {
+    let p = project()
+        .file(
+            "Cargo.toml",
+            r#"
+            [project]
+            name = "foo"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies]
+            bar = { path = "bar" }
+
+            [workspace]
+        "#,
+        )
+        .file("src/main.rs", "fn main() {}")
+        .file(
+            "bar/Cargo.toml",
+            r#"
+            [project]
+            name = "bar"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies]
+            i-dont-exist = "0.55"
+        "#,
+        )
+        .file("bar/src/main.rs", "fn main() {}")
+        .build();
+
+    let config = Config::default().unwrap();
+    let ws = Workspace::new(&p.root().join("Cargo.toml"), &config).unwrap();
+    let compile_options = CompileOptions::new(&config, CompileMode::Build).unwrap();
+    let member_bar = ws.members().find(|m| &*m.name() == "bar").unwrap();
+
+    let error = ops::compile(&ws, &compile_options).map(|_| ()).unwrap_err();
+    eprintln!("{:?}", error);
+
+    let package_err: &PackageError = error.downcast_ref().expect("Not a PackageError");
+    assert_eq!(package_err.package_id(), member_bar.package_id());
+}