1
1
use std:: fmt;
2
+ use std:: fmt:: Write as _;
2
3
use std:: task:: Poll ;
3
4
4
5
use crate :: core:: { Dependency , PackageId , Registry , Summary } ;
5
6
use crate :: sources:: source:: QueryKind ;
7
+ use crate :: sources:: IndexSummary ;
6
8
use crate :: util:: edit_distance:: edit_distance;
7
9
use crate :: util:: { GlobalContext , OptVersionReq , VersionExt } ;
8
10
use anyhow:: Error ;
@@ -301,10 +303,23 @@ pub(super) fn activation_error(
301
303
302
304
msg
303
305
} else {
306
+ // Maybe something is wrong with the available versions
307
+ let mut version_candidates = loop {
308
+ match registry. query_vec ( & new_dep, QueryKind :: AlternativeVersions ) {
309
+ Poll :: Ready ( Ok ( candidates) ) => break candidates,
310
+ Poll :: Ready ( Err ( e) ) => return to_resolve_err ( e) ,
311
+ Poll :: Pending => match registry. block_until_ready ( ) {
312
+ Ok ( ( ) ) => continue ,
313
+ Err ( e) => return to_resolve_err ( e) ,
314
+ } ,
315
+ }
316
+ } ;
317
+ version_candidates. sort_unstable_by_key ( |a| a. as_summary ( ) . version ( ) . clone ( ) ) ;
318
+
304
319
// Maybe the user mistyped the name? Like `dep-thing` when `Dep_Thing`
305
320
// was meant. So we try asking the registry for a `fuzzy` search for suggestions.
306
- let candidates = loop {
307
- match registry. query_vec ( & new_dep, QueryKind :: Alternatives ) {
321
+ let name_candidates = loop {
322
+ match registry. query_vec ( & new_dep, QueryKind :: AlternativeNames ) {
308
323
Poll :: Ready ( Ok ( candidates) ) => break candidates,
309
324
Poll :: Ready ( Err ( e) ) => return to_resolve_err ( e) ,
310
325
Poll :: Pending => match registry. block_until_ready ( ) {
@@ -313,58 +328,102 @@ pub(super) fn activation_error(
313
328
} ,
314
329
}
315
330
} ;
316
-
317
- let mut candidates: Vec < _ > = candidates. into_iter ( ) . map ( |s| s. into_summary ( ) ) . collect ( ) ;
318
-
319
- candidates. sort_unstable_by_key ( |a| a. name ( ) ) ;
320
- candidates. dedup_by ( |a, b| a. name ( ) == b. name ( ) ) ;
321
- let mut candidates: Vec < _ > = candidates
331
+ let mut name_candidates: Vec < _ > = name_candidates
332
+ . into_iter ( )
333
+ . map ( |s| s. into_summary ( ) )
334
+ . collect ( ) ;
335
+ name_candidates. sort_unstable_by_key ( |a| a. name ( ) ) ;
336
+ name_candidates. dedup_by ( |a, b| a. name ( ) == b. name ( ) ) ;
337
+ let mut name_candidates: Vec < _ > = name_candidates
322
338
. iter ( )
323
339
. filter_map ( |n| Some ( ( edit_distance ( & * new_dep. package_name ( ) , & * n. name ( ) , 3 ) ?, n) ) )
324
340
. collect ( ) ;
325
- candidates . sort_by_key ( |o| o. 0 ) ;
326
- let mut msg : String ;
327
- if candidates . is_empty ( ) {
328
- msg = format ! ( "no matching package named `{}` found \n " , dep . package_name ( ) ) ;
329
- } else {
330
- msg = format ! (
331
- "no matching package found \n searched package name: `{}`\n " ,
341
+ name_candidates . sort_by_key ( |o| o. 0 ) ;
342
+
343
+ let mut msg = String :: new ( ) ;
344
+ if !version_candidates . is_empty ( ) {
345
+ let _ = writeln ! (
346
+ & mut msg ,
347
+ "no matching versions for `{}` found " ,
332
348
dep. package_name( )
333
349
) ;
334
- let mut names = candidates
350
+ for candidate in version_candidates {
351
+ match candidate {
352
+ IndexSummary :: Candidate ( summary) => {
353
+ // HACK: If this was a real candidate, we wouldn't hit this case.
354
+ // so it must be a patch which get normalized to being a candidate
355
+ let _ =
356
+ writeln ! ( & mut msg, " version {} is unavailable" , summary. version( ) ) ;
357
+ }
358
+ IndexSummary :: Yanked ( summary) => {
359
+ let _ = writeln ! ( & mut msg, " version {} is yanked" , summary. version( ) ) ;
360
+ }
361
+ IndexSummary :: Offline ( summary) => {
362
+ let _ = writeln ! ( & mut msg, " version {} is not cached" , summary. version( ) ) ;
363
+ }
364
+ IndexSummary :: Unsupported ( summary, schema_version) => {
365
+ if let Some ( rust_version) = summary. rust_version ( ) {
366
+ // HACK: technically its unsupported and we shouldn't make assumptions
367
+ // about the entry but this is limited and for diagnostics purposes
368
+ let _ = writeln ! (
369
+ & mut msg,
370
+ " version {} requires cargo {}" ,
371
+ summary. version( ) ,
372
+ rust_version
373
+ ) ;
374
+ } else {
375
+ let _ = writeln ! (
376
+ & mut msg,
377
+ " version {} requires a Cargo version that supports index version {}" ,
378
+ summary. version( ) ,
379
+ schema_version
380
+ ) ;
381
+ }
382
+ }
383
+ }
384
+ }
385
+ } else if !name_candidates. is_empty ( ) {
386
+ let _ = writeln ! ( & mut msg, "no matching package found" , ) ;
387
+ let _ = writeln ! ( & mut msg, "searched package name: `{}`" , dep. package_name( ) ) ;
388
+ let mut names = name_candidates
335
389
. iter ( )
336
390
. take ( 3 )
337
391
. map ( |c| c. 1 . name ( ) . as_str ( ) )
338
392
. collect :: < Vec < _ > > ( ) ;
339
393
340
- if candidates . len ( ) > 3 {
394
+ if name_candidates . len ( ) > 3 {
341
395
names. push ( "..." ) ;
342
396
}
343
397
// Vertically align first suggestion with missing crate name
344
398
// so a typo jumps out at you.
345
- msg . push_str ( "perhaps you meant: " ) ;
346
- msg . push_str ( & names . iter ( ) . enumerate ( ) . fold (
347
- String :: default ( ) ,
348
- |acc, ( i, el) | match i {
399
+ let suggestions = names
400
+ . iter ( )
401
+ . enumerate ( )
402
+ . fold ( String :: default ( ) , |acc, ( i, el) | match i {
349
403
0 => acc + el,
350
- i if names. len ( ) - 1 == i && candidates . len ( ) <= 3 => acc + " or " + el,
404
+ i if names. len ( ) - 1 == i && name_candidates . len ( ) <= 3 => acc + " or " + el,
351
405
_ => acc + ", " + el,
352
- } ,
353
- ) ) ;
354
- msg. push ( '\n' ) ;
406
+ } ) ;
407
+ let _ = writeln ! ( & mut msg, "perhaps you meant: {suggestions}" ) ;
408
+ } else {
409
+ let _ = writeln ! (
410
+ & mut msg,
411
+ "no matching package named `{}` found" ,
412
+ dep. package_name( )
413
+ ) ;
355
414
}
356
415
357
416
let mut location_searched_msg = registry. describe_source ( dep. source_id ( ) ) ;
358
417
if location_searched_msg. is_empty ( ) {
359
418
location_searched_msg = format ! ( "{}" , dep. source_id( ) ) ;
360
419
}
361
420
362
- msg . push_str ( & format ! ( "location searched: {}\n " , location_searched_msg) ) ;
363
- msg . push_str ( "required by " ) ;
364
- msg . push_str ( & describe_path_in_context (
365
- resolver_ctx ,
366
- & parent. package_id ( ) ,
367
- ) ) ;
421
+ let _ = writeln ! ( & mut msg , "location searched: {}" , location_searched_msg) ;
422
+ let _ = write ! (
423
+ & mut msg ,
424
+ "required by {}" ,
425
+ describe_path_in_context ( resolver_ctx , & parent. package_id( ) ) ,
426
+ ) ;
368
427
369
428
msg
370
429
} ;
0 commit comments