@@ -17,6 +17,7 @@ use crate::util::{style, OptVersionReq};
17
17
use crate :: util:: { CargoResult , VersionExt } ;
18
18
use anyhow:: Context as _;
19
19
use cargo_util_schemas:: core:: PartialVersion ;
20
+ use indexmap:: IndexMap ;
20
21
use itertools:: Itertools ;
21
22
use semver:: { Op , Version , VersionReq } ;
22
23
use std:: cmp:: Ordering ;
@@ -491,16 +492,16 @@ fn print_lockfile_generation(
491
492
resolve : & Resolve ,
492
493
registry : & mut PackageRegistry < ' _ > ,
493
494
) -> CargoResult < ( ) > {
494
- let diff : Vec < _ > = PackageDiff :: new ( & resolve) . collect ( ) ;
495
- let num_pkgs: usize = diff . iter ( ) . map ( |d| d . added . len ( ) ) . sum ( ) ;
495
+ let changes = PackageChange :: new ( resolve) ;
496
+ let num_pkgs: usize = changes . iter ( ) . filter ( |change| change . kind . is_new ( ) ) . count ( ) ;
496
497
if num_pkgs <= 1 {
497
498
// just ourself, nothing worth reporting
498
499
return Ok ( ( ) ) ;
499
500
}
500
501
status_locking ( ws, num_pkgs) ?;
501
502
502
- for diff in diff {
503
- let possibilities = if let Some ( query) = diff . alternatives_query ( ) {
503
+ for change in changes {
504
+ let possibilities = if let Some ( query) = change . alternatives_query ( ) {
504
505
loop {
505
506
match registry. query_vec ( & query, QueryKind :: Exact ) {
506
507
std:: task:: Poll :: Ready ( res) => {
@@ -513,12 +514,14 @@ fn print_lockfile_generation(
513
514
vec ! [ ]
514
515
} ;
515
516
516
- for package_id in diff. added {
517
+ {
518
+ let package_id = change. package_id ;
517
519
let required_rust_version = report_required_rust_version ( ws, resolve, package_id) ;
518
520
let latest = report_latest ( & possibilities, package_id) ;
519
521
let note = required_rust_version. or ( latest) ;
520
522
521
523
if let Some ( note) = note {
524
+ assert_eq ! ( change. kind, PackageChangeKind :: Added ) ;
522
525
ws. gctx ( ) . shell ( ) . status_with_color (
523
526
"Adding" ,
524
527
format ! ( "{package_id}{note}" ) ,
@@ -537,15 +540,15 @@ fn print_lockfile_sync(
537
540
resolve : & Resolve ,
538
541
registry : & mut PackageRegistry < ' _ > ,
539
542
) -> CargoResult < ( ) > {
540
- let diff : Vec < _ > = PackageDiff :: diff ( & previous_resolve, & resolve) . collect ( ) ;
541
- let num_pkgs: usize = diff . iter ( ) . map ( |d| d . added . len ( ) ) . sum ( ) ;
543
+ let changes = PackageChange :: diff ( previous_resolve, resolve) ;
544
+ let num_pkgs: usize = changes . iter ( ) . filter ( |change| change . kind . is_new ( ) ) . count ( ) ;
542
545
if num_pkgs == 0 {
543
546
return Ok ( ( ) ) ;
544
547
}
545
548
status_locking ( ws, num_pkgs) ?;
546
549
547
- for diff in diff {
548
- let possibilities = if let Some ( query) = diff . alternatives_query ( ) {
550
+ for change in changes {
551
+ let possibilities = if let Some ( query) = change . alternatives_query ( ) {
549
552
loop {
550
553
match registry. query_vec ( & query, QueryKind :: Exact ) {
551
554
std:: task:: Poll :: Ready ( res) => {
@@ -558,7 +561,8 @@ fn print_lockfile_sync(
558
561
vec ! [ ]
559
562
} ;
560
563
561
- if let Some ( ( previous_id, package_id) ) = diff. change ( ) {
564
+ let package_id = change. package_id ;
565
+ if let Some ( previous_id) = change. previous_id {
562
566
let required_rust_version = report_required_rust_version ( ws, resolve, package_id) ;
563
567
let latest = report_latest ( & possibilities, package_id) ;
564
568
let note = required_rust_version. or ( latest) . unwrap_or_default ( ) ;
@@ -572,11 +576,7 @@ fn print_lockfile_sync(
572
576
format ! ( "{previous_id} -> v{}{note}" , package_id. version( ) )
573
577
} ;
574
578
575
- // If versions differ only in build metadata, we call it an "update"
576
- // regardless of whether the build metadata has gone up or down.
577
- // This metadata is often stuff like git commit hashes, which are
578
- // not meaningfully ordered.
579
- if previous_id. version ( ) . cmp_precedence ( package_id. version ( ) ) == Ordering :: Greater {
579
+ if change. kind == PackageChangeKind :: Downgraded {
580
580
ws. gctx ( )
581
581
. shell ( )
582
582
. status_with_color ( "Downgrading" , msg, & style:: WARN ) ?;
@@ -586,7 +586,7 @@ fn print_lockfile_sync(
586
586
. status_with_color ( "Updating" , msg, & style:: GOOD ) ?;
587
587
}
588
588
} else {
589
- for package_id in diff . added {
589
+ if change . kind == PackageChangeKind :: Added {
590
590
let required_rust_version = report_required_rust_version ( ws, resolve, package_id) ;
591
591
let latest = report_latest ( & possibilities, package_id) ;
592
592
let note = required_rust_version. or ( latest) . unwrap_or_default ( ) ;
@@ -610,15 +610,15 @@ fn print_lockfile_updates(
610
610
precise : bool ,
611
611
registry : & mut PackageRegistry < ' _ > ,
612
612
) -> CargoResult < ( ) > {
613
- let diff : Vec < _ > = PackageDiff :: diff ( & previous_resolve, & resolve) . collect ( ) ;
614
- let num_pkgs: usize = diff . iter ( ) . map ( |d| d . added . len ( ) ) . sum ( ) ;
613
+ let changes = PackageChange :: diff ( previous_resolve, resolve) ;
614
+ let num_pkgs: usize = changes . iter ( ) . filter ( |change| change . kind . is_new ( ) ) . count ( ) ;
615
615
if !precise {
616
616
status_locking ( ws, num_pkgs) ?;
617
617
}
618
618
619
619
let mut unchanged_behind = 0 ;
620
- for diff in diff {
621
- let possibilities = if let Some ( query) = diff . alternatives_query ( ) {
620
+ for change in changes {
621
+ let possibilities = if let Some ( query) = change . alternatives_query ( ) {
622
622
loop {
623
623
match registry. query_vec ( & query, QueryKind :: Exact ) {
624
624
std:: task:: Poll :: Ready ( res) => {
@@ -631,7 +631,8 @@ fn print_lockfile_updates(
631
631
vec ! [ ]
632
632
} ;
633
633
634
- if let Some ( ( previous_id, package_id) ) = diff. change ( ) {
634
+ let package_id = change. package_id ;
635
+ if let Some ( previous_id) = change. previous_id {
635
636
let required_rust_version = report_required_rust_version ( ws, resolve, package_id) ;
636
637
let latest = report_latest ( & possibilities, package_id) ;
637
638
let note = required_rust_version. or ( latest) . unwrap_or_default ( ) ;
@@ -645,11 +646,7 @@ fn print_lockfile_updates(
645
646
format ! ( "{previous_id} -> v{}{note}" , package_id. version( ) )
646
647
} ;
647
648
648
- // If versions differ only in build metadata, we call it an "update"
649
- // regardless of whether the build metadata has gone up or down.
650
- // This metadata is often stuff like git commit hashes, which are
651
- // not meaningfully ordered.
652
- if previous_id. version ( ) . cmp_precedence ( package_id. version ( ) ) == Ordering :: Greater {
649
+ if change. kind == PackageChangeKind :: Downgraded {
653
650
ws. gctx ( )
654
651
. shell ( )
655
652
. status_with_color ( "Downgrading" , msg, & style:: WARN ) ?;
@@ -659,14 +656,13 @@ fn print_lockfile_updates(
659
656
. status_with_color ( "Updating" , msg, & style:: GOOD ) ?;
660
657
}
661
658
} else {
662
- for package_id in diff . removed {
659
+ if change . kind == PackageChangeKind :: Removed {
663
660
ws. gctx ( ) . shell ( ) . status_with_color (
664
661
"Removing" ,
665
662
format ! ( "{package_id}" ) ,
666
663
& style:: ERROR ,
667
664
) ?;
668
- }
669
- for package_id in diff. added {
665
+ } else if change. kind == PackageChangeKind :: Added {
670
666
let required_rust_version = report_required_rust_version ( ws, resolve, package_id) ;
671
667
let latest = report_latest ( & possibilities, package_id) ;
672
668
let note = required_rust_version. or ( latest) . unwrap_or_default ( ) ;
@@ -678,7 +674,7 @@ fn print_lockfile_updates(
678
674
) ?;
679
675
}
680
676
}
681
- for package_id in diff . unchanged {
677
+ if change . kind == PackageChangeKind :: Unchanged {
682
678
let required_rust_version = report_required_rust_version ( ws, resolve, package_id) ;
683
679
let latest = report_latest ( & possibilities, package_id) ;
684
680
let note = required_rust_version. as_deref ( ) . or ( latest. as_deref ( ) ) ;
@@ -818,6 +814,113 @@ fn fill_with_deps<'a>(
818
814
}
819
815
}
820
816
817
+ #[ derive( Clone , Debug ) ]
818
+ struct PackageChange {
819
+ package_id : PackageId ,
820
+ previous_id : Option < PackageId > ,
821
+ kind : PackageChangeKind ,
822
+ }
823
+
824
+ impl PackageChange {
825
+ pub fn new ( resolve : & Resolve ) -> Vec < Self > {
826
+ let diff = PackageDiff :: new ( resolve) ;
827
+ Self :: with_diff ( diff)
828
+ }
829
+
830
+ pub fn diff ( previous_resolve : & Resolve , resolve : & Resolve ) -> Vec < Self > {
831
+ let diff = PackageDiff :: diff ( previous_resolve, resolve) ;
832
+ Self :: with_diff ( diff)
833
+ }
834
+
835
+ fn with_diff ( diff : impl Iterator < Item = PackageDiff > ) -> Vec < Self > {
836
+ let mut changes = IndexMap :: new ( ) ;
837
+ for diff in diff {
838
+ if let Some ( ( previous_id, package_id) ) = diff. change ( ) {
839
+ // If versions differ only in build metadata, we call it an "update"
840
+ // regardless of whether the build metadata has gone up or down.
841
+ // This metadata is often stuff like git commit hashes, which are
842
+ // not meaningfully ordered.
843
+ let kind = if previous_id. version ( ) . cmp_precedence ( package_id. version ( ) )
844
+ == Ordering :: Greater
845
+ {
846
+ PackageChangeKind :: Downgraded
847
+ } else {
848
+ PackageChangeKind :: Upgraded
849
+ } ;
850
+ let change = Self {
851
+ package_id,
852
+ previous_id : Some ( previous_id) ,
853
+ kind,
854
+ } ;
855
+ changes. insert ( change. package_id , change) ;
856
+ } else {
857
+ for package_id in diff. removed {
858
+ let kind = PackageChangeKind :: Removed ;
859
+ let change = Self {
860
+ package_id,
861
+ previous_id : None ,
862
+ kind,
863
+ } ;
864
+ changes. insert ( change. package_id , change) ;
865
+ }
866
+ for package_id in diff. added {
867
+ let kind = PackageChangeKind :: Added ;
868
+ let change = Self {
869
+ package_id,
870
+ previous_id : None ,
871
+ kind,
872
+ } ;
873
+ changes. insert ( change. package_id , change) ;
874
+ }
875
+ }
876
+ for package_id in diff. unchanged {
877
+ let kind = PackageChangeKind :: Unchanged ;
878
+ let change = Self {
879
+ package_id,
880
+ previous_id : None ,
881
+ kind,
882
+ } ;
883
+ changes. insert ( change. package_id , change) ;
884
+ }
885
+ }
886
+
887
+ changes. into_values ( ) . collect ( )
888
+ }
889
+
890
+ /// For querying [`PackageRegistry`] for alternative versions to report to the user
891
+ fn alternatives_query ( & self ) -> Option < crate :: core:: dependency:: Dependency > {
892
+ if !self . package_id . source_id ( ) . is_registry ( ) {
893
+ return None ;
894
+ }
895
+
896
+ let query = crate :: core:: dependency:: Dependency :: parse (
897
+ self . package_id . name ( ) ,
898
+ None ,
899
+ self . package_id . source_id ( ) ,
900
+ )
901
+ . expect ( "already a valid dependency" ) ;
902
+ Some ( query)
903
+ }
904
+ }
905
+
906
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
907
+ enum PackageChangeKind {
908
+ Added ,
909
+ Removed ,
910
+ Upgraded ,
911
+ Downgraded ,
912
+ Unchanged ,
913
+ }
914
+
915
+ impl PackageChangeKind {
916
+ pub fn is_new ( & self ) -> bool {
917
+ match self {
918
+ Self :: Added | Self :: Upgraded | Self :: Downgraded => true ,
919
+ Self :: Removed | Self :: Unchanged => false ,
920
+ }
921
+ }
922
+ }
923
+
821
924
/// All resolved versions of a package name within a [`SourceId`]
822
925
#[ derive( Default , Clone , Debug ) ]
823
926
pub struct PackageDiff {
@@ -931,25 +1034,4 @@ impl PackageDiff {
931
1034
None
932
1035
}
933
1036
}
934
-
935
- /// For querying [`PackageRegistry`] for alternative versions to report to the user
936
- pub fn alternatives_query ( & self ) -> Option < crate :: core:: dependency:: Dependency > {
937
- let package_id = [
938
- self . added . iter ( ) ,
939
- self . unchanged . iter ( ) ,
940
- self . removed . iter ( ) ,
941
- ]
942
- . into_iter ( )
943
- . flatten ( )
944
- . next ( )
945
- // Limit to registry as that is the only source with meaningful alternative versions
946
- . filter ( |s| s. source_id ( ) . is_registry ( ) ) ?;
947
- let query = crate :: core:: dependency:: Dependency :: parse (
948
- package_id. name ( ) ,
949
- None ,
950
- package_id. source_id ( ) ,
951
- )
952
- . expect ( "already a valid dependency" ) ;
953
- Some ( query)
954
- }
955
1037
}
0 commit comments