Skip to content

Commit

Permalink
Auto merge of #7191 - debris:prerelease_error_message, r=Eh2406
Browse files Browse the repository at this point in the history
improve error message for unmatched prerelease dependencies

fixes #7007

error message before:

```
error: no matching package named `a` found
location searched: [..]
perhaps you meant: a
required by package `b v0.1.0 ([..])`
```

error message now

```
error: no matching package named `a` found
location searched: [..]
prerelease package needs to be specified explicitly
a = { version = "0.1.1-alpha.0" }
required by package `b v0.1.0 ([..])`
```
  • Loading branch information
bors committed Aug 1, 2019
2 parents 26092da + 577968e commit 85b9566
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 86 deletions.
187 changes: 101 additions & 86 deletions src/cargo/core/resolver/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,100 +203,115 @@ pub(super) fn activation_error(
};
candidates.sort_unstable_by(|a, b| b.version().cmp(a.version()));

let mut msg = if !candidates.is_empty() {
let versions = {
let mut versions = candidates
.iter()
.take(3)
.map(|cand| cand.version().to_string())
.collect::<Vec<_>>();
let mut msg =
if !candidates.is_empty() {
let versions = {
let mut versions = candidates
.iter()
.take(3)
.map(|cand| cand.version().to_string())
.collect::<Vec<_>>();

if candidates.len() > 3 {
versions.push("...".into());
}

versions.join(", ")
};

let mut msg = format!(
"failed to select a version for the requirement `{} = \"{}\"`\n \
candidate versions found which didn't match: {}\n \
location searched: {}\n",
dep.package_name(),
dep.version_req(),
versions,
registry.describe_source(dep.source_id()),
);
msg.push_str("required by ");
msg.push_str(&describe_path(
&cx.parents.path_to_bottom(&parent.package_id()),
));

if candidates.len() > 3 {
versions.push("...".into());
// If we have a path dependency with a locked version, then this may
// indicate that we updated a sub-package and forgot to run `cargo
// update`. In this case try to print a helpful error!
if dep.source_id().is_path() && dep.version_req().to_string().starts_with('=') {
msg.push_str(
"\nconsider running `cargo update` to update \
a path dependency's locked version",
);
}

versions.join(", ")
};

let mut msg = format!(
"failed to select a version for the requirement `{} = \"{}\"`\n \
candidate versions found which didn't match: {}\n \
location searched: {}\n",
dep.package_name(),
dep.version_req(),
versions,
registry.describe_source(dep.source_id()),
);
msg.push_str("required by ");
msg.push_str(&describe_path(
&cx.parents.path_to_bottom(&parent.package_id()),
));

// If we have a path dependency with a locked version, then this may
// indicate that we updated a sub-package and forgot to run `cargo
// update`. In this case try to print a helpful error!
if dep.source_id().is_path() && dep.version_req().to_string().starts_with('=') {
msg.push_str(
"\nconsider running `cargo update` to update \
a path dependency's locked version",
);
}

if registry.is_replaced(dep.source_id()) {
msg.push_str("\nperhaps a crate was updated and forgotten to be re-vendored?");
}
if registry.is_replaced(dep.source_id()) {
msg.push_str("\nperhaps a crate was updated and forgotten to be re-vendored?");
}

msg
} else {
// Maybe the user mistyped the name? Like `dep-thing` when `Dep_Thing`
// 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 to_resolve_err(e);
};
candidates.sort_unstable();
candidates.dedup();
let mut candidates: Vec<_> = candidates
.iter()
.map(|n| (lev_distance(&*new_dep.package_name(), &*n), n))
.filter(|&(d, _)| d < 4)
.collect();
candidates.sort_by_key(|o| o.0);
let mut msg = format!(
"no matching package named `{}` found\n\
location searched: {}\n",
dep.package_name(),
dep.source_id()
);
if !candidates.is_empty() {
let mut names = candidates
msg
} else {
// Maybe the user mistyped the name? Like `dep-thing` when `Dep_Thing`
// 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.clone()), true) {
return to_resolve_err(e);
};
candidates.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
candidates.dedup_by(|a, b| a.name() == b.name());
let mut candidates: Vec<_> = candidates
.iter()
.take(3)
.map(|c| c.1.as_str())
.collect::<Vec<_>>();

if candidates.len() > 3 {
names.push("...");
.map(|n| (lev_distance(&*new_dep.package_name(), &*n.name()), n))
.filter(|&(d, _)| d < 4)
.collect();
candidates.sort_by_key(|o| o.0);
let mut msg = format!(
"no matching package named `{}` found\n\
location searched: {}\n",
dep.package_name(),
dep.source_id()
);
if !candidates.is_empty() {
// If dependency package name is equal to the name of the candidate here
// it may be a prerelease package which hasn't been speficied correctly
if dep.package_name() == candidates[0].1.name()
&& candidates[0].1.package_id().version().is_prerelease()
{
msg.push_str("prerelease package needs to be specified explicitly\n");
msg.push_str(&format!(
"{name} = {{ version = \"{version}\" }}",
name = candidates[0].1.name(),
version = candidates[0].1.package_id().version()
));
} else {
let mut names = candidates
.iter()
.take(3)
.map(|c| c.1.name().as_str())
.collect::<Vec<_>>();

if candidates.len() > 3 {
names.push("...");
}

msg.push_str("perhaps you meant: ");
msg.push_str(&names.iter().enumerate().fold(
String::default(),
|acc, (i, el)| match i {
0 => acc + el,
i if names.len() - 1 == i && candidates.len() <= 3 => acc + " or " + el,
_ => acc + ", " + el,
},
));
}

msg.push_str("\n");
}

msg.push_str("perhaps you meant: ");
msg.push_str(&names.iter().enumerate().fold(
String::default(),
|acc, (i, el)| match i {
0 => acc + el,
i if names.len() - 1 == i && candidates.len() <= 3 => acc + " or " + el,
_ => acc + ", " + el,
},
msg.push_str("required by ");
msg.push_str(&describe_path(
&cx.parents.path_to_bottom(&parent.package_id()),
));
msg.push_str("\n");
}
msg.push_str("required by ");
msg.push_str(&describe_path(
&cx.parents.path_to_bottom(&parent.package_id()),
));

msg
};
msg
};

if let Some(config) = config {
if config.offline() {
Expand Down
49 changes: 49 additions & 0 deletions tests/testsuite/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,55 @@ fn use_semver() {
p.cargo("build").run();
}

#[cargo_test]
fn use_semver_package_incorrectly() {
let p = project()
.file(
"Cargo.toml",
r#"
[workspace]
members = ["a", "b"]
"#,
)
.file(
"a/Cargo.toml",
r#"
[project]
name = "a"
version = "0.1.1-alpha.0"
authors = []
"#,
)
.file(
"b/Cargo.toml",
r#"
[project]
name = "b"
version = "0.1.0"
authors = []
[dependencies]
a = { version = "^0.1", path = "../a" }
"#,
)
.file("a/src/main.rs", "fn main() {}")
.file("b/src/main.rs", "fn main() {}")
.build();

p.cargo("build")
.with_status(101)
.with_stderr(
"\
error: no matching package named `a` found
location searched: [..]
prerelease package needs to be specified explicitly
a = { version = \"0.1.1-alpha.0\" }
required by package `b v0.1.0 ([..])`
",
)
.run();
}

#[cargo_test]
fn only_download_relevant() {
let p = project()
Expand Down

0 comments on commit 85b9566

Please sign in to comment.