@@ -226,7 +226,11 @@ pub struct RecursivePathSource<'gctx> {
226
226
/// Whether this source has loaded all package information it may contain.
227
227
loaded : bool ,
228
228
/// Packages that this sources has discovered.
229
- packages : HashMap < PackageId , Package > ,
229
+ ///
230
+ /// Tracking all packages for a given ID to warn on-demand for unused packages
231
+ packages : HashMap < PackageId , Vec < Package > > ,
232
+ /// Avoid redundant unused package warnings
233
+ warned_duplicate : HashSet < PackageId > ,
230
234
gctx : & ' gctx GlobalContext ,
231
235
}
232
236
@@ -245,6 +249,7 @@ impl<'gctx> RecursivePathSource<'gctx> {
245
249
path : root. to_path_buf ( ) ,
246
250
loaded : false ,
247
251
packages : Default :: default ( ) ,
252
+ warned_duplicate : Default :: default ( ) ,
248
253
gctx,
249
254
}
250
255
}
@@ -253,7 +258,13 @@ impl<'gctx> RecursivePathSource<'gctx> {
253
258
/// filesystem if package information haven't yet loaded.
254
259
pub fn read_packages ( & mut self ) -> CargoResult < Vec < Package > > {
255
260
self . load ( ) ?;
256
- Ok ( self . packages . iter ( ) . map ( |( _, v) | v. clone ( ) ) . collect ( ) )
261
+ Ok ( self
262
+ . packages
263
+ . iter ( )
264
+ . map ( |( pkg_id, v) | {
265
+ first_package ( * pkg_id, v, & mut self . warned_duplicate , self . gctx ) . clone ( )
266
+ } )
267
+ . collect ( ) )
257
268
}
258
269
259
270
/// List all files relevant to building this package inside this source.
@@ -311,7 +322,15 @@ impl<'gctx> Source for RecursivePathSource<'gctx> {
311
322
f : & mut dyn FnMut ( IndexSummary ) ,
312
323
) -> Poll < CargoResult < ( ) > > {
313
324
self . load ( ) ?;
314
- for s in self . packages . values ( ) . map ( |p| p. summary ( ) ) {
325
+ for s in self
326
+ . packages
327
+ . iter ( )
328
+ . filter ( |( pkg_id, _) | pkg_id. name ( ) == dep. package_name ( ) )
329
+ . map ( |( pkg_id, pkgs) | {
330
+ first_package ( * pkg_id, pkgs, & mut self . warned_duplicate , self . gctx )
331
+ } )
332
+ . map ( |p| p. summary ( ) )
333
+ {
315
334
let matched = match kind {
316
335
QueryKind :: Exact => dep. matches ( s) ,
317
336
QueryKind :: Alternatives => true ,
@@ -340,7 +359,7 @@ impl<'gctx> Source for RecursivePathSource<'gctx> {
340
359
trace ! ( "getting packages; id={}" , id) ;
341
360
self . load ( ) ?;
342
361
let pkg = self . packages . get ( & id) ;
343
- pkg. cloned ( )
362
+ pkg. map ( |pkgs| first_package ( id , pkgs , & mut self . warned_duplicate , self . gctx ) . clone ( ) )
344
363
. map ( MaybePackage :: Ready )
345
364
. ok_or_else ( || internal ( format ! ( "failed to find {} in path source" , id) ) )
346
365
}
@@ -384,6 +403,38 @@ impl<'gctx> Source for RecursivePathSource<'gctx> {
384
403
}
385
404
}
386
405
406
+ fn first_package < ' p > (
407
+ pkg_id : PackageId ,
408
+ pkgs : & ' p Vec < Package > ,
409
+ warned_duplicate : & mut HashSet < PackageId > ,
410
+ gctx : & GlobalContext ,
411
+ ) -> & ' p Package {
412
+ if pkgs. len ( ) != 1 && warned_duplicate. insert ( pkg_id) {
413
+ let ignored = pkgs[ 1 ..]
414
+ . iter ( )
415
+ // We can assume a package with publish = false isn't intended to be seen
416
+ // by users so we can hide the warning about those since the user is unlikely
417
+ // to care about those cases.
418
+ . filter ( |pkg| pkg. publish ( ) . is_none ( ) )
419
+ . collect :: < Vec < _ > > ( ) ;
420
+ if !ignored. is_empty ( ) {
421
+ use std:: fmt:: Write as _;
422
+
423
+ let plural = if ignored. len ( ) == 1 { "" } else { "s" } ;
424
+ let mut msg = String :: new ( ) ;
425
+ let _ = writeln ! ( & mut msg, "skipping duplicate package{plural} `{pkg_id}`:" ) ;
426
+ for ignored in ignored {
427
+ let manifest_path = ignored. manifest_path ( ) . display ( ) ;
428
+ let _ = writeln ! ( & mut msg, " {manifest_path}" ) ;
429
+ }
430
+ let manifest_path = pkgs[ 0 ] . manifest_path ( ) . display ( ) ;
431
+ let _ = writeln ! ( & mut msg, "in favor of {manifest_path}" ) ;
432
+ let _ = gctx. shell ( ) . warn ( msg) ;
433
+ }
434
+ }
435
+ & pkgs[ 0 ]
436
+ }
437
+
387
438
/// List all files relevant to building this package inside this source.
388
439
///
389
440
/// This function will use the appropriate methods to determine the
@@ -758,7 +809,7 @@ fn read_packages(
758
809
path : & Path ,
759
810
source_id : SourceId ,
760
811
gctx : & GlobalContext ,
761
- ) -> CargoResult < HashMap < PackageId , Package > > {
812
+ ) -> CargoResult < HashMap < PackageId , Vec < Package > > > {
762
813
let mut all_packages = HashMap :: new ( ) ;
763
814
let mut visited = HashSet :: < PathBuf > :: new ( ) ;
764
815
let mut errors = Vec :: < anyhow:: Error > :: new ( ) ;
@@ -882,6 +933,8 @@ fn walk(path: &Path, callback: &mut dyn FnMut(&Path) -> CargoResult<bool>) -> Ca
882
933
return Err ( e. context ( cx) ) ;
883
934
}
884
935
} ;
936
+ let mut dirs = dirs. collect :: < Vec < _ > > ( ) ;
937
+ dirs. sort_unstable_by_key ( |d| d. as_ref ( ) . ok ( ) . map ( |d| d. file_name ( ) ) ) ;
885
938
for dir in dirs {
886
939
let dir = dir?;
887
940
if dir. file_type ( ) ?. is_dir ( ) {
@@ -897,7 +950,7 @@ fn has_manifest(path: &Path) -> bool {
897
950
898
951
fn read_nested_packages (
899
952
path : & Path ,
900
- all_packages : & mut HashMap < PackageId , Package > ,
953
+ all_packages : & mut HashMap < PackageId , Vec < Package > > ,
901
954
source_id : SourceId ,
902
955
gctx : & GlobalContext ,
903
956
visited : & mut HashSet < PathBuf > ,
@@ -936,24 +989,7 @@ fn read_nested_packages(
936
989
let pkg = Package :: new ( manifest, & manifest_path) ;
937
990
938
991
let pkg_id = pkg. package_id ( ) ;
939
- use std:: collections:: hash_map:: Entry ;
940
- match all_packages. entry ( pkg_id) {
941
- Entry :: Vacant ( v) => {
942
- v. insert ( pkg) ;
943
- }
944
- Entry :: Occupied ( _) => {
945
- // We can assume a package with publish = false isn't intended to be seen
946
- // by users so we can hide the warning about those since the user is unlikely
947
- // to care about those cases.
948
- if pkg. publish ( ) . is_none ( ) {
949
- let _ = gctx. shell ( ) . warn ( format ! (
950
- "skipping duplicate package `{}` found at `{}`" ,
951
- pkg. name( ) ,
952
- path. display( )
953
- ) ) ;
954
- }
955
- }
956
- }
992
+ all_packages. entry ( pkg_id) . or_default ( ) . push ( pkg) ;
957
993
958
994
// Registry sources are not allowed to have `path=` dependencies because
959
995
// they're all translated to actual registry dependencies.
0 commit comments