Expose manifest error chain

This commit is contained in:
Alex Butler 2018-10-09 14:05:10 +01:00
parent 5fc8ac71e8
commit 49ab03e3b0
No known key found for this signature in database
GPG Key ID: E1355A2F8E415521
4 changed files with 159 additions and 5 deletions

View File

@ -1,6 +1,7 @@
use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::BTreeMap;
use std::io;
use std::path::{Path, PathBuf};
use std::slice;
@ -13,7 +14,7 @@ use core::{Dependency, PackageIdSpec};
use core::{EitherManifest, Package, SourceId, VirtualManifest};
use ops;
use sources::PathSource;
use util::errors::{CargoResult, CargoResultExt};
use util::errors::{CargoResult, CargoResultExt, ManifestError};
use util::paths;
use util::toml::read_manifest;
use util::{Config, Filesystem};
@ -495,9 +496,21 @@ impl<'cfg> Workspace<'cfg> {
self.members.push(manifest_path.clone());
let candidates = {
let pkg = match *self.packages.load(&manifest_path)? {
MaybePackage::Package(ref p) => p,
MaybePackage::Virtual(_) => return Ok(()),
let pkg = match self.packages.load(&manifest_path) {
Ok(MaybePackage::Package(ref p)) => p,
Ok(MaybePackage::Virtual(_)) => return Ok(()),
Err(err) => {
return Err(if err
.iter_chain()
.any(|e| e.downcast_ref::<io::Error>().is_some() )
{
// don't wrap io errors to ensure ManifestErrors
// are for actual existing manifests
err
} else {
ManifestError::new(err, manifest_path).into()
});
}
};
pkg.dependencies()
.iter()
@ -508,7 +521,8 @@ impl<'cfg> Workspace<'cfg> {
.collect::<Vec<_>>()
};
for candidate in candidates {
self.find_path_deps(&candidate, root_manifest, true)?;
self.find_path_deps(&candidate, root_manifest, true)
.map_err(|err| ManifestError::new(err, manifest_path.clone()))?;
}
Ok(())
}

View File

@ -3,6 +3,7 @@
use std::fmt;
use std::process::{ExitStatus, Output};
use std::str;
use std::path::PathBuf;
use core::{TargetKind, Workspace};
use failure::{Context, Error, Fail};
@ -72,6 +73,40 @@ impl fmt::Display for Internal {
}
}
/// Error related to a particular manifest and providing it's path.
pub struct ManifestError {
cause: Error,
manifest: PathBuf,
}
impl ManifestError {
pub fn new(cause: Error, manifest: PathBuf) -> Self {
Self { cause, manifest }
}
pub fn manifest_path(&self) -> &PathBuf {
&self.manifest
}
}
impl Fail for ManifestError {
fn cause(&self) -> Option<&Fail> {
self.cause.as_fail().into()
}
}
impl fmt::Debug for ManifestError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.cause.fmt(f)
}
}
impl fmt::Display for ManifestError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.cause.fmt(f)
}
}
// =============================================================================
// Process errors
#[derive(Debug, Fail)]

View File

@ -66,6 +66,7 @@ mod jobserver;
mod local_registry;
mod lockfile_compat;
mod login;
mod member_errors;
mod metabuild;
mod metadata;
mod net_config;

View File

@ -0,0 +1,104 @@
use cargo::core::Workspace;
use cargo::util::{config::Config, errors::ManifestError};
use support::project;
/// Tests inclusion of a `ManifestError` pointing to a member manifest
/// when that manifest fails to deserialize.
#[test]
fn toml_deserialize_manifest_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]
foobar == "0.55"
"#,
)
.file("bar/src/main.rs", "fn main() {}")
.build();
let root_manifest_path = p.root().join("Cargo.toml");
let member_manifest_path = p.root().join("bar").join("Cargo.toml");
let error = Workspace::new(&root_manifest_path, &Config::default().unwrap()).unwrap_err();
eprintln!("{:?}", error);
let manifest_err = error
.iter_chain()
.filter_map(|err| err.downcast_ref::<ManifestError>())
.last()
.expect("No ManifestError");
assert_eq!(manifest_err.manifest_path(), &member_manifest_path);
}
/// Tests inclusion of a `ManifestError` pointing to a member manifest
/// when that manifest has an invalid dependency path.
#[test]
fn member_manifest_path_io_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]
foobar = { path = "nosuch" }
"#,
)
.file("bar/src/main.rs", "fn main() {}")
.build();
let root_manifest_path = p.root().join("Cargo.toml");
let member_manifest_path = p.root().join("bar").join("Cargo.toml");
let error = Workspace::new(&root_manifest_path, &Config::default().unwrap()).unwrap_err();
eprintln!("{:?}", error);
let manifest_err = error
.iter_chain()
.filter_map(|err| err.downcast_ref::<ManifestError>())
.last()
.expect("No ManifestError");
assert_eq!(manifest_err.manifest_path(), &member_manifest_path);
}