Improve the error message for ambiguous specs

This commit is contained in:
Alex Crichton 2014-09-26 21:45:51 -07:00
parent 217ff7fb93
commit 37dbfd2ec6
2 changed files with 94 additions and 9 deletions

View file

@ -1,5 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::collections::hashmap::{Occupied, Vacant};
use std::collections::hashmap::{HashMap, HashSet, Occupied, Vacant};
use std::fmt;
use semver;
@ -222,17 +221,44 @@ impl Resolve {
None => return Err(human(format!("package id specification `{}` \
matched no packages", spec))),
};
match ids.next() {
return match ids.next() {
Some(other) => {
let mut msg = format!("Ambiguous package id specification: \
`{}`\nMatching packages:\n {}\n {}",
spec, ret, other);
for id in ids {
msg = format!("{}\n {}", msg, id);
}
let mut msg = format!("There are multiple `{}` packages in \
your project, and the specification \
`{}` is ambiguous.\n\
Please re-run this command \
with `-p <spec>` where `<spec>` is one \
of the following:",
spec.get_name(), spec);
let mut vec = vec![ret, other];
vec.extend(ids);
minimize(&mut msg, vec, &spec);
Err(human(msg))
}
None => Ok(ret)
};
fn minimize(msg: &mut String,
ids: Vec<&PackageId>,
spec: &PackageIdSpec) {
let mut version_cnt = HashMap::new();
for id in ids.iter() {
let slot = match version_cnt.entry(id.get_version()) {
Occupied(e) => e.into_mut(),
Vacant(e) => e.set(0u),
};
*slot += 1;
}
for id in ids.iter() {
if version_cnt[id.get_version()] == 1 {
msg.push_str(format!("\n {}:{}", spec.get_name(),
id.get_version()).as_slice());
} else {
msg.push_str(format!("\n {}",
PackageIdSpec::from_package_id(*id))
.as_slice());
}
}
}
}

View file

@ -1328,3 +1328,62 @@ test!(warnings_in_git_dep {
COMPILING, p.url()))
.with_stderr(""));
})
test!(update_ambiguous {
let foo1 = git_repo("foo1", |project| {
project.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
}).assert();
let foo2 = git_repo("foo2", |project| {
project.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.6.0"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
}).assert();
let bar = git_repo("bar", |project| {
project.file("Cargo.toml", format!(r#"
[package]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.foo]
git = '{}'
"#, foo2.url()).as_slice())
.file("src/lib.rs", "")
}).assert();
let p = project("project")
.file("Cargo.toml", format!(r#"
[project]
name = "project"
version = "0.5.0"
authors = []
[dependencies.foo]
git = '{}'
[dependencies.bar]
git = '{}'
"#, foo1.url(), bar.url()).as_slice())
.file("src/main.rs", "fn main() {}");
assert_that(p.cargo_process("generate-lockfile"), execs().with_status(0));
assert_that(p.process(cargo_dir().join("cargo")).arg("update")
.arg("-p").arg("foo"),
execs().with_status(101)
.with_stderr("\
There are multiple `foo` packages in your project, and the specification `foo` \
is ambiguous.
Please re-run this command with `-p <spec>` where `<spec>` is one of the \
following:
foo:0.[..].0
foo:0.[..].0
"));
})