@@ -154,7 +154,7 @@ impl EncodableResolve {
154
154
/// primary uses is to be used with `resolve_with_previous` to guide the
155
155
/// resolver to create a complete Resolve.
156
156
pub fn into_resolve ( self , original : & str , ws : & Workspace < ' _ > ) -> CargoResult < Resolve > {
157
- let path_deps = build_path_deps ( ws) ?;
157
+ let path_deps = PathDeps :: from_workspace ( ws) ?;
158
158
let mut checksums = HashMap :: new ( ) ;
159
159
160
160
let mut version = match self . version {
@@ -202,14 +202,18 @@ impl EncodableResolve {
202
202
if !all_pkgs. insert ( enc_id. clone ( ) ) {
203
203
anyhow:: bail!( "package `{}` is specified twice in the lockfile" , pkg. name) ;
204
204
}
205
- let id = match pkg. source . as_deref ( ) . or_else ( || path_deps. get ( & pkg. name ) ) {
205
+ let id = match pkg. source . as_deref ( ) . copied ( ) . or_else ( || {
206
+ path_deps
207
+ . get_path_dep ( & pkg. name , & pkg. version )
208
+ . map ( |package_id| package_id. source_id ( ) )
209
+ } ) {
206
210
// We failed to find a local package in the workspace.
207
211
// It must have been removed and should be ignored.
208
212
None => {
209
213
debug ! ( "path dependency now missing {} v{}" , pkg. name, pkg. version) ;
210
214
continue ;
211
215
}
212
- Some ( & source) => PackageId :: try_new ( & pkg. name , & pkg. version , source) ?,
216
+ Some ( source) => PackageId :: try_new ( & pkg. name , & pkg. version , source) ?,
213
217
} ;
214
218
215
219
// If a package has a checksum listed directly on it then record
@@ -364,8 +368,12 @@ impl EncodableResolve {
364
368
365
369
let mut unused_patches = Vec :: new ( ) ;
366
370
for pkg in self . patch . unused {
367
- let id = match pkg. source . as_deref ( ) . or_else ( || path_deps. get ( & pkg. name ) ) {
368
- Some ( & src) => PackageId :: try_new ( & pkg. name , & pkg. version , src) ?,
371
+ let id = match pkg. source . as_deref ( ) . copied ( ) . or_else ( || {
372
+ path_deps
373
+ . get_path_dep ( & pkg. name , & pkg. version )
374
+ . map ( |package_id| package_id. source_id ( ) )
375
+ } ) {
376
+ Some ( src) => PackageId :: try_new ( & pkg. name , & pkg. version , src) ?,
369
377
None => continue ,
370
378
} ;
371
379
unused_patches. push ( id) ;
@@ -408,68 +416,98 @@ impl EncodableResolve {
408
416
}
409
417
}
410
418
411
- fn build_path_deps ( ws : & Workspace < ' _ > ) -> CargoResult < HashMap < String , SourceId > > {
412
- // If a crate is **not** a path source, then we're probably in a situation
413
- // such as `cargo install` with a lock file from a remote dependency. In
414
- // that case we don't need to fixup any path dependencies (as they're not
415
- // actually path dependencies any more), so we ignore them.
416
- let members = ws
417
- . members ( )
418
- . filter ( |p| p. package_id ( ) . source_id ( ) . is_path ( ) )
419
- . collect :: < Vec < _ > > ( ) ;
420
-
421
- let mut ret = HashMap :: new ( ) ;
422
- let mut visited = HashSet :: new ( ) ;
423
- for member in members. iter ( ) {
424
- ret. insert (
425
- member. package_id ( ) . name ( ) . to_string ( ) ,
426
- member. package_id ( ) . source_id ( ) ,
427
- ) ;
428
- visited. insert ( member. package_id ( ) . source_id ( ) ) ;
429
- }
430
- for member in members. iter ( ) {
431
- build_pkg ( member, ws, & mut ret, & mut visited) ;
419
+ struct PathDeps {
420
+ path_deps : HashMap < String , Vec < PackageId > > ,
421
+ }
422
+
423
+ impl PathDeps {
424
+ /// Get a best-effort path dependency with given constraints.
425
+ ///
426
+ /// If no exact version match, pickup a random version for patch updating trial
427
+ fn get_path_dep ( & self , name : & str , version : & str ) -> Option < & PackageId > {
428
+ let pkg_version = semver:: Version :: parse ( version) . ok ( ) ?;
429
+ self . path_deps . get ( name) . and_then ( |versions| {
430
+ versions
431
+ . iter ( )
432
+ . find ( |package_id| {
433
+ package_id. version ( ) . cmp_precedence ( & pkg_version) == std:: cmp:: Ordering :: Equal
434
+ } )
435
+ . or_else ( || versions. last ( ) )
436
+ } )
432
437
}
433
- for deps in ws. root_patch ( ) ?. values ( ) {
434
- for dep in deps {
438
+
439
+ /// Return all path dependencies recursively in given workspace
440
+ fn from_workspace ( ws : & Workspace < ' _ > ) -> CargoResult < Self > {
441
+ // If a crate is **not** a path source, then we're probably in a situation
442
+ // such as `cargo install` with a lock file from a remote dependency. In
443
+ // that case we don't need to fixup any path dependencies (as they're not
444
+ // actually path dependencies any more), so we ignore them.
445
+ let members = ws
446
+ . members ( )
447
+ . filter ( |p| p. package_id ( ) . source_id ( ) . is_path ( ) )
448
+ . collect :: < Vec < _ > > ( ) ;
449
+
450
+ let mut ret = HashSet :: new ( ) ;
451
+ let mut visited = HashSet :: new ( ) ;
452
+ for member in members. iter ( ) {
453
+ ret. insert ( member. package_id ( ) ) ;
454
+ visited. insert ( member. package_id ( ) . source_id ( ) ) ;
455
+ }
456
+ for member in members. iter ( ) {
457
+ build_pkg ( member, ws, & mut ret, & mut visited) ;
458
+ }
459
+ for deps in ws. root_patch ( ) ?. values ( ) {
460
+ for dep in deps {
461
+ build_dep ( dep, ws, & mut ret, & mut visited) ;
462
+ }
463
+ }
464
+ for ( _, dep) in ws. root_replace ( ) {
435
465
build_dep ( dep, ws, & mut ret, & mut visited) ;
436
466
}
437
- }
438
- for ( _, dep) in ws. root_replace ( ) {
439
- build_dep ( dep, ws, & mut ret, & mut visited) ;
440
- }
441
467
442
- return Ok ( ret) ;
468
+ let path_deps = {
469
+ // Mapping from package name to package ids
470
+ let mut deps: HashMap < String , Vec < PackageId > > = HashMap :: new ( ) ;
471
+ for package_id in ret {
472
+ deps. entry ( package_id. name ( ) . to_string ( ) )
473
+ . or_default ( )
474
+ . push ( package_id) ;
475
+ }
476
+ deps
477
+ } ;
478
+
479
+ return Ok ( Self { path_deps } ) ;
443
480
444
- fn build_pkg (
445
- pkg : & Package ,
446
- ws : & Workspace < ' _ > ,
447
- ret : & mut HashMap < String , SourceId > ,
448
- visited : & mut HashSet < SourceId > ,
449
- ) {
450
- for dep in pkg. dependencies ( ) {
451
- build_dep ( dep, ws, ret, visited) ;
481
+ fn build_pkg (
482
+ pkg : & Package ,
483
+ ws : & Workspace < ' _ > ,
484
+ ret : & mut HashSet < PackageId > ,
485
+ visited : & mut HashSet < SourceId > ,
486
+ ) {
487
+ for dep in pkg. dependencies ( ) {
488
+ build_dep ( dep, ws, ret, visited) ;
489
+ }
452
490
}
453
- }
454
491
455
- fn build_dep (
456
- dep : & Dependency ,
457
- ws : & Workspace < ' _ > ,
458
- ret : & mut HashMap < String , SourceId > ,
459
- visited : & mut HashSet < SourceId > ,
460
- ) {
461
- let id = dep. source_id ( ) ;
462
- if visited. contains ( & id) || !id. is_path ( ) {
463
- return ;
492
+ fn build_dep (
493
+ dep : & Dependency ,
494
+ ws : & Workspace < ' _ > ,
495
+ ret : & mut HashSet < PackageId > ,
496
+ visited : & mut HashSet < SourceId > ,
497
+ ) {
498
+ let id = dep. source_id ( ) ;
499
+ if visited. contains ( & id) || !id. is_path ( ) {
500
+ return ;
501
+ }
502
+ let path = match id. url ( ) . to_file_path ( ) {
503
+ Ok ( p) => p. join ( "Cargo.toml" ) ,
504
+ Err ( _) => return ,
505
+ } ;
506
+ let Ok ( pkg) = ws. load ( & path) else { return } ;
507
+ ret. insert ( pkg. package_id ( ) ) ;
508
+ visited. insert ( pkg. package_id ( ) . source_id ( ) ) ;
509
+ build_pkg ( & pkg, ws, ret, visited) ;
464
510
}
465
- let path = match id. url ( ) . to_file_path ( ) {
466
- Ok ( p) => p. join ( "Cargo.toml" ) ,
467
- Err ( _) => return ,
468
- } ;
469
- let Ok ( pkg) = ws. load ( & path) else { return } ;
470
- ret. insert ( pkg. name ( ) . to_string ( ) , pkg. package_id ( ) . source_id ( ) ) ;
471
- visited. insert ( pkg. package_id ( ) . source_id ( ) ) ;
472
- build_pkg ( & pkg, ws, ret, visited) ;
473
511
}
474
512
}
475
513
0 commit comments