Skip to content

Commit 84cc3d8

Browse files
committed
allow each source to recommend packages that are close to a dependency
1 parent 8a717d3 commit 84cc3d8

File tree

12 files changed

+110
-30
lines changed

12 files changed

+110
-30
lines changed

src/cargo/core/registry.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ use sources::config::SourceConfigMap;
1414
/// See also `core::Source`.
1515
pub trait Registry {
1616
/// Attempt to find the packages that match a dependency request.
17-
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()>;
17+
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary), fuzzy: bool) -> CargoResult<()>;
1818

19-
fn query_vec(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
19+
fn query_vec(&mut self, dep: &Dependency, fuzzy: bool) -> CargoResult<Vec<Summary>> {
2020
let mut ret = Vec::new();
21-
self.query(dep, &mut |s| ret.push(s))?;
21+
self.query(dep, &mut |s| ret.push(s), fuzzy)?;
2222
Ok(ret)
2323
}
2424
}
@@ -395,7 +395,7 @@ http://doc.crates.io/specifying-dependencies.html#overriding-dependencies
395395
}
396396

397397
impl<'cfg> Registry for PackageRegistry<'cfg> {
398-
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
398+
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary), fuzzy: bool) -> CargoResult<()> {
399399
assert!(self.patches_locked);
400400
let (override_summary, n, to_warn) = {
401401
// Look for an override and get ready to query the real source.
@@ -476,15 +476,20 @@ impl<'cfg> Registry for PackageRegistry<'cfg> {
476476
// already selected, then we skip this `summary`.
477477
let locked = &self.locked;
478478
let all_patches = &self.patches_available;
479-
return source.query(dep, &mut |summary| {
479+
let callback = &mut |summary: Summary| {
480480
for patch in patches.iter() {
481481
let patch = patch.package_id().version();
482482
if summary.package_id().version() == patch {
483483
return;
484484
}
485485
}
486486
f(lock(locked, all_patches, summary))
487-
});
487+
};
488+
return if fuzzy {
489+
source.fuzzy_query(dep, callback)
490+
} else {
491+
source.query(dep, callback)
492+
};
488493
}
489494

490495
// If we have an override summary then we query the source
@@ -496,10 +501,17 @@ impl<'cfg> Registry for PackageRegistry<'cfg> {
496501
}
497502
let mut n = 0;
498503
let mut to_warn = None;
499-
source.query(dep, &mut |summary| {
500-
n += 1;
501-
to_warn = Some(summary);
502-
})?;
504+
{
505+
let callback = &mut |summary| {
506+
n += 1;
507+
to_warn = Some(summary);
508+
};
509+
if fuzzy {
510+
source.fuzzy_query(dep, callback)?;
511+
} else {
512+
source.query(dep, callback)?;
513+
}
514+
}
503515
(override_summary, n, to_warn)
504516
}
505517
}

src/cargo/core/resolver/mod.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -922,17 +922,16 @@ fn activation_error(
922922
return format_err!("{}", msg);
923923
}
924924

925-
// Once we're all the way down here, we're definitely lost in the
926-
// weeds! We didn't actually find any candidates, so we need to
925+
// We didn't actually find any candidates, so we need to
927926
// give an error message that nothing was found.
928927
//
929-
// Note that we re-query the registry with a new dependency that
930-
// allows any version so we can give some nicer error reporting
931-
// which indicates a few versions that were actually found.
928+
// Maybe the user mistyped the ver_req? Like `dep="2"` when `dep=".2"`
929+
// was meant. So we re-query the registry with `deb="*"` so we can
930+
// list a few versions that were actually found.
932931
let all_req = semver::VersionReq::parse("*").unwrap();
933932
let mut new_dep = dep.clone();
934933
new_dep.set_version_req(all_req);
935-
let mut candidates = match registry.query_vec(&new_dep) {
934+
let mut candidates = match registry.query_vec(&new_dep, false) {
936935
Ok(candidates) => candidates,
937936
Err(e) => return e,
938937
};
@@ -977,12 +976,25 @@ fn activation_error(
977976

978977
msg
979978
} else {
979+
// Maybe the user mistyped the name? Like `dep-thing` when `Dep_Thing`
980+
// was meant. So we try asking the registry for a `fuzzy` search for suggestions.
981+
let mut candidates = Vec::new();
982+
if let Err(e) = registry.query(&new_dep, &mut |s| candidates.push(s.name()), true) {
983+
return e
984+
};
985+
candidates.sort_unstable();
986+
candidates.dedup();
980987
let mut msg = format!(
981988
"no matching package named `{}` found\n\
982989
location searched: {}\n",
983990
dep.name(),
984991
dep.source_id()
985992
);
993+
if !candidates.is_empty() {
994+
msg.push_str("did you mean: ");
995+
msg.push_str(&candidates.join(" or "));
996+
msg.push_str("\n");
997+
}
986998
msg.push_str("required by ");
987999
msg.push_str(&describe_path(&graph.path_to_top(parent.package_id())));
9881000

src/cargo/core/resolver/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<'a> RegistryQueryer<'a> {
5252
summary: s,
5353
replace: None,
5454
});
55-
})?;
55+
}, false)?;
5656
for candidate in ret.iter_mut() {
5757
let summary = &candidate.summary;
5858

@@ -66,7 +66,7 @@ impl<'a> RegistryQueryer<'a> {
6666
};
6767
debug!("found an override for {} {}", dep.name(), dep.version_req());
6868

69-
let mut summaries = self.registry.query_vec(dep)?.into_iter();
69+
let mut summaries = self.registry.query_vec(dep, false)?.into_iter();
7070
let s = summaries.next().ok_or_else(|| {
7171
format_err!(
7272
"no matching package for override `{}` found\n\

src/cargo/core/source/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ pub trait Source {
2525
/// Attempt to find the packages that match a dependency request.
2626
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()>;
2727

28+
/// Attempt to find the packages that are close to a dependency request.
29+
/// Each source gets to define what `close` means for it.
30+
/// path/git sources may return all dependencies that are at that uri.
31+
/// where as an Index source may return dependencies that have the same canonicalization.
32+
fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()>;
33+
2834
fn query_vec(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
2935
let mut ret = Vec::new();
3036
self.query(dep, &mut |s| ret.push(s))?;
@@ -79,6 +85,11 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
7985
(**self).query(dep, f)
8086
}
8187

88+
/// Forwards to `Source::query`
89+
fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
90+
(**self).fuzzy_query(dep, f)
91+
}
92+
8293
/// Forwards to `Source::source_id`
8394
fn source_id(&self) -> &SourceId {
8495
(**self).source_id()

src/cargo/sources/directory.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ impl<'cfg> Source for DirectorySource<'cfg> {
5454
Ok(())
5555
}
5656

57+
fn fuzzy_query(&mut self, _dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
58+
let packages = self.packages.values().map(|p| &p.0);
59+
for summary in packages.map(|pkg| pkg.summary().clone()) {
60+
f(summary);
61+
}
62+
Ok(())
63+
}
64+
5765
fn supports_checksums(&self) -> bool {
5866
true
5967
}

src/cargo/sources/git/source.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ impl<'cfg> Source for GitSource<'cfg> {
130130
src.query(dep, f)
131131
}
132132

133+
fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
134+
let src = self.path_source
135+
.as_mut()
136+
.expect("BUG: update() must be called before query()");
137+
src.fuzzy_query(dep, f)
138+
}
139+
133140
fn supports_checksums(&self) -> bool {
134141
false
135142
}

src/cargo/sources/path.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,13 @@ impl<'cfg> Source for PathSource<'cfg> {
508508
Ok(())
509509
}
510510

511+
fn fuzzy_query(&mut self, _dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
512+
for s in self.packages.iter().map(|p| p.summary()) {
513+
f(s.clone())
514+
}
515+
Ok(())
516+
}
517+
511518
fn supports_checksums(&self) -> bool {
512519
false
513520
}

src/cargo/sources/registry/index.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ impl<'cfg> RegistryIndex<'cfg> {
208208
Ok((summary, yanked.unwrap_or(false)))
209209
}
210210

211-
pub fn query(
211+
pub fn query_inner(
212212
&mut self,
213213
dep: &Dependency,
214214
load: &mut RegistryData,
@@ -242,9 +242,7 @@ impl<'cfg> RegistryIndex<'cfg> {
242242
});
243243

244244
for summary in summaries {
245-
if dep.matches(&summary) {
246-
f(summary);
247-
}
245+
f(summary);
248246
}
249247
Ok(())
250248
}

src/cargo/sources/registry/mod.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -463,9 +463,11 @@ impl<'cfg> Source for RegistrySource<'cfg> {
463463
if dep.source_id().precise().is_some() && !self.updated {
464464
debug!("attempting query without update");
465465
let mut called = false;
466-
self.index.query(dep, &mut *self.ops, &mut |s| {
467-
called = true;
468-
f(s);
466+
self.index.query_inner(dep, &mut *self.ops, &mut |s| {
467+
if dep.matches(&s) {
468+
called = true;
469+
f(s);
470+
}
469471
})?;
470472
if called {
471473
return Ok(());
@@ -475,7 +477,15 @@ impl<'cfg> Source for RegistrySource<'cfg> {
475477
}
476478
}
477479

478-
self.index.query(dep, &mut *self.ops, f)
480+
self.index.query_inner(dep, &mut *self.ops, &mut |s| {
481+
if dep.matches(&s) {
482+
f(s);
483+
}
484+
})
485+
}
486+
487+
fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
488+
self.index.query_inner(dep, &mut *self.ops, f)
479489
}
480490

481491
fn supports_checksums(&self) -> bool {

src/cargo/sources/replaced.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ impl<'cfg> Source for ReplacedSource<'cfg> {
3535
Ok(())
3636
}
3737

38+
fn fuzzy_query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
39+
let (replace_with, to_replace) = (&self.replace_with, &self.to_replace);
40+
let dep = dep.clone().map_source(to_replace, replace_with);
41+
42+
self.inner
43+
.fuzzy_query(
44+
&dep,
45+
&mut |summary| f(summary.map_source(replace_with, to_replace)),
46+
)
47+
.chain_err(|| format!("failed to query replaced source {}", self.to_replace))?;
48+
Ok(())
49+
}
50+
3851
fn supports_checksums(&self) -> bool {
3952
self.inner.supports_checksums()
4053
}

tests/testsuite/registry.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,15 @@ fn wrong_case() {
161161
.file("src/main.rs", "fn main() {}")
162162
.build();
163163

164-
// TODO: #5678 to make this work or at least give better error message
164+
// #5678 to make this work
165165
assert_that(
166166
p.cargo("build"),
167167
execs().with_status(101).with_stderr(
168168
"\
169169
[UPDATING] registry [..]
170170
error: no matching package named `Init` found
171171
location searched: registry [..]
172+
did you mean: init
172173
required by package `foo v0.0.1 ([..])`
173174
",
174175
),
@@ -195,14 +196,15 @@ fn mis_hyphenated() {
195196
.file("src/main.rs", "fn main() {}")
196197
.build();
197198

198-
// TODO: #2775 to make this work or at least give better error message
199+
// #2775 to make this work
199200
assert_that(
200201
p.cargo("build"),
201202
execs().with_status(101).with_stderr(
202203
"\
203204
[UPDATING] registry [..]
204205
error: no matching package named `mis_hyphenated` found
205206
location searched: registry [..]
207+
did you mean: mis-hyphenated
206208
required by package `foo v0.0.1 ([..])`
207209
",
208210
),

tests/testsuite/resolve.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ fn resolve_with_config(
2828
) -> CargoResult<Vec<PackageId>> {
2929
struct MyRegistry<'a>(&'a [Summary]);
3030
impl<'a> Registry for MyRegistry<'a> {
31-
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary)) -> CargoResult<()> {
31+
fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary), fuzzy: bool) -> CargoResult<()> {
3232
for summary in self.0.iter() {
33-
if dep.matches(summary) {
33+
if fuzzy || dep.matches(summary) {
3434
f(summary.clone());
3535
}
3636
}

0 commit comments

Comments
 (0)