Skip to content

Commit

Permalink
Make multi-version warning report dependency chain
Browse files Browse the repository at this point in the history
  • Loading branch information
schuster committed Jul 6, 2016
1 parent c7204e3 commit 7ee0a85
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 13 deletions.
51 changes: 42 additions & 9 deletions src/cargo/ops/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::{BTreeSet, HashMap, HashSet};
use std::collections::{BTreeSet, HashMap, HashSet, VecDeque};

use semver;

Expand Down Expand Up @@ -182,15 +182,16 @@ fn warn_if_multiple_versions(resolved: &Resolve,
for ((package_name, package_source), versions) in package_version_map {
let old_version_count = previous_version_map.get(&(package_name, package_source))
.unwrap_or(&BTreeSet::new()).len();

if versions.len() > 1 && old_version_count <= 1 {
try!(config.shell().warn(format!(
"using multiple versions of crate \"{}\"\nversions: {}",
package_name,
versions.into_iter()
.map(|v| format!("v{}", v))
.collect::<Vec<String>>()
.join(", "))));
let mut warning = format!("using multiple versions of crate \"{}\"", package_name);

for version in versions {
let target = try!(PackageId::new(package_name, version, package_source));
let replaced = resolved.replacement(&target).unwrap_or(&target);
warning = warning + "\n" + &try!(path_to_package(resolved, &replaced));
}

try!(config.shell().warn(warning));
}
}

Expand All @@ -208,3 +209,35 @@ fn build_version_map(resolved: &Resolve) -> HashMap<(&str, &SourceId), BTreeSet<

package_version_map
}

// Implements a breadth-first search to get the shortest path from the root package to a given
// target package
fn path_to_package(resolved: &Resolve, target_id: &PackageId) -> CargoResult<String> {
let mut queue : VecDeque<(&PackageId, Vec<&PackageId>)> = VecDeque::new();
queue.push_back((resolved.root(), vec![]));
let mut visited = HashSet::new();

while !queue.is_empty() {
let (current_id, path) = queue.pop_front().unwrap();
if current_id == target_id {
let mut path_string = String::new();
for id in path {
path_string = path_string + &format!("{} v{} -> ", id.name(), id.version());
}
return Ok(path_string + &format!("{} v{}", current_id.name(), current_id.version()));
}

visited.insert(current_id);
for dependency_package_id in resolved.deps(current_id) {
if !visited.contains(dependency_package_id) {
let mut path = path.clone();
path.push(current_id);
queue.push_back((dependency_package_id, path));
}
}
}

// This should never happen; path_to_package should only be called with a Resolve that has the
// target package in it
panic!("(unable to find dependency path to {} v{})", target_id.name(), target_id.version())
}
3 changes: 2 additions & 1 deletion tests/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2288,7 +2288,8 @@ fn warn_about_multiple_versions() {
execs().with_status(0)
.with_stderr_contains("\
[WARNING] using multiple versions of crate \"bar\"
versions: v0.0.1, v0.0.2
foo v0.0.1 -> bar v0.0.1
foo v0.0.1 -> baz v0.0.1 -> bar v0.0.2
"));

assert_that(p.cargo("build"),
Expand Down
3 changes: 2 additions & 1 deletion tests/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ fn warn_about_multiple_versions() {
execs().with_status(0)
.with_stderr_contains("\
[WARNING] using multiple versions of crate \"bar\"
versions: v0.0.1, v0.0.2
foo v0.0.1 -> bar v0.0.1
foo v0.0.1 -> baz v0.0.1 -> bar v0.0.2
"));

// Warning should be generated only once
Expand Down
6 changes: 4 additions & 2 deletions tests/generate-lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ fn warn_about_multiple_versions_on_generate() {
execs().with_status(0)
.with_stderr_contains("\
[WARNING] using multiple versions of crate \"bar\"
versions: v0.0.1, v0.0.2
foo v0.0.1 -> bar v0.0.1
foo v0.0.1 -> baz v0.0.1 -> bar v0.0.2
"));
}

Expand All @@ -251,7 +252,8 @@ fn warn_about_multiple_versions_on_update() {
execs().with_status(0)
.with_stderr_contains("\
[WARNING] using multiple versions of crate \"bar\"
versions: v0.0.1, v0.0.2
foo v0.0.1 -> bar v0.0.1
foo v0.0.1 -> baz v0.0.1 -> bar v0.0.2
"));

assert_that(p.cargo("update"),
Expand Down
1 change: 1 addition & 0 deletions tests/overrides.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ fn use_a_spec_to_select() {
[UPDATING] git repository `[..]`
[WARNING] [..]
[..]
[..]
[DOWNLOADING] [..]
[DOWNLOADING] [..]
[COMPILING] [..]
Expand Down

0 comments on commit 7ee0a85

Please sign in to comment.