@@ -175,11 +175,14 @@ pub(crate) async fn lock(
175175 {
176176 Ok ( lock) => {
177177 if dry_run {
178- let changed = if let LockResult :: Changed ( previous, lock) = & lock {
179- report_upgrades ( previous. as_ref ( ) , lock, printer, dry_run) ?
180- } else {
181- false
182- } ;
178+ // In `--dry-run` mode, show all changes.
179+ let mut changed = false ;
180+ if let LockResult :: Changed ( previous, lock) = & lock {
181+ for event in LockEvent :: detect_changes ( previous. as_ref ( ) , lock, dry_run) {
182+ changed = true ;
183+ writeln ! ( printer. stderr( ) , "{event}" ) ?;
184+ }
185+ }
183186 if !changed {
184187 writeln ! (
185188 printer. stderr( ) ,
@@ -189,7 +192,9 @@ pub(crate) async fn lock(
189192 }
190193 } else {
191194 if let LockResult :: Changed ( Some ( previous) , lock) = & lock {
192- report_upgrades ( Some ( previous) , lock, printer, dry_run) ?;
195+ for event in LockEvent :: detect_changes ( Some ( previous) , lock, dry_run) {
196+ writeln ! ( printer. stderr( ) , "{event}" ) ?;
197+ }
193198 }
194199 }
195200
@@ -1072,104 +1077,138 @@ impl ValidatedLock {
10721077 }
10731078}
10741079
1075- /// Reports on the versions that were upgraded in the new lockfile.
1076- ///
1077- /// Returns `true` if any upgrades were reported.
1078- fn report_upgrades (
1079- existing_lock : Option < & Lock > ,
1080- new_lock : & Lock ,
1081- printer : Printer ,
1082- dry_run : bool ,
1083- ) -> anyhow:: Result < bool > {
1084- let existing_packages: FxHashMap < & PackageName , BTreeSet < Option < & Version > > > =
1085- if let Some ( existing_lock) = existing_lock {
1086- existing_lock. packages ( ) . iter ( ) . fold (
1087- FxHashMap :: with_capacity_and_hasher ( existing_lock. packages ( ) . len ( ) , FxBuildHasher ) ,
1080+ /// A modification to a lockfile.
1081+ #[ derive( Debug , Clone ) ]
1082+ pub ( crate ) enum LockEvent < ' lock > {
1083+ Update (
1084+ bool ,
1085+ PackageName ,
1086+ BTreeSet < Option < & ' lock Version > > ,
1087+ BTreeSet < Option < & ' lock Version > > ,
1088+ ) ,
1089+ Add ( bool , PackageName , BTreeSet < Option < & ' lock Version > > ) ,
1090+ Remove ( bool , PackageName , BTreeSet < Option < & ' lock Version > > ) ,
1091+ }
1092+
1093+ impl < ' lock > LockEvent < ' lock > {
1094+ /// Detect the change events between an (optional) existing and updated lockfile.
1095+ pub ( crate ) fn detect_changes (
1096+ existing_lock : Option < & ' lock Lock > ,
1097+ new_lock : & ' lock Lock ,
1098+ dry_run : bool ,
1099+ ) -> impl Iterator < Item = Self > {
1100+ // Identify the package-versions in the existing lockfile.
1101+ let mut existing_packages: FxHashMap < & PackageName , BTreeSet < Option < & Version > > > =
1102+ if let Some ( existing_lock) = existing_lock {
1103+ existing_lock. packages ( ) . iter ( ) . fold (
1104+ FxHashMap :: with_capacity_and_hasher (
1105+ existing_lock. packages ( ) . len ( ) ,
1106+ FxBuildHasher ,
1107+ ) ,
1108+ |mut acc, package| {
1109+ acc. entry ( package. name ( ) )
1110+ . or_default ( )
1111+ . insert ( package. version ( ) ) ;
1112+ acc
1113+ } ,
1114+ )
1115+ } else {
1116+ FxHashMap :: default ( )
1117+ } ;
1118+
1119+ // Identify the package-versions in the updated lockfile.
1120+ let mut new_packages: FxHashMap < & PackageName , BTreeSet < Option < & Version > > > =
1121+ new_lock. packages ( ) . iter ( ) . fold (
1122+ FxHashMap :: with_capacity_and_hasher ( new_lock. packages ( ) . len ( ) , FxBuildHasher ) ,
10881123 |mut acc, package| {
10891124 acc. entry ( package. name ( ) )
10901125 . or_default ( )
10911126 . insert ( package. version ( ) ) ;
10921127 acc
10931128 } ,
1094- )
1095- } else {
1096- FxHashMap :: default ( )
1097- } ;
1129+ ) ;
10981130
1099- let new_distributions: FxHashMap < & PackageName , BTreeSet < Option < & Version > > > =
1100- new_lock. packages ( ) . iter ( ) . fold (
1101- FxHashMap :: with_capacity_and_hasher ( new_lock. packages ( ) . len ( ) , FxBuildHasher ) ,
1102- |mut acc, package| {
1103- acc. entry ( package. name ( ) )
1104- . or_default ( )
1105- . insert ( package. version ( ) ) ;
1106- acc
1107- } ,
1108- ) ;
1131+ let names = existing_packages
1132+ . keys ( )
1133+ . chain ( new_packages. keys ( ) )
1134+ . map ( |name| ( * name) . clone ( ) )
1135+ . collect :: < BTreeSet < _ > > ( ) ;
1136+
1137+ names. into_iter ( ) . filter_map ( move |name| {
1138+ match ( existing_packages. remove ( & name) , new_packages. remove ( & name) ) {
1139+ ( Some ( existing_versions) , Some ( new_versions) ) => {
1140+ if existing_versions != new_versions {
1141+ Some ( Self :: Update ( dry_run, name, existing_versions, new_versions) )
1142+ } else {
1143+ None
1144+ }
1145+ }
1146+ ( Some ( existing_versions) , None ) => {
1147+ Some ( Self :: Remove ( dry_run, name, existing_versions) )
1148+ }
1149+ ( None , Some ( new_versions) ) => Some ( Self :: Add ( dry_run, name, new_versions) ) ,
1150+ ( None , None ) => {
1151+ unreachable ! ( "The key `{name}` should exist in at least one of the maps" ) ;
1152+ }
1153+ }
1154+ } )
1155+ }
1156+ }
11091157
1110- let mut updated = false ;
1111- for name in existing_packages
1112- . keys ( )
1113- . chain ( new_distributions. keys ( ) )
1114- . collect :: < BTreeSet < _ > > ( )
1115- {
1158+ impl std:: fmt:: Display for LockEvent < ' _ > {
1159+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
11161160 /// Format a version for inclusion in the upgrade report.
11171161 fn format_version ( version : Option < & Version > ) -> String {
11181162 version
11191163 . map ( |version| format ! ( "v{version}" ) )
11201164 . unwrap_or_else ( || "(dynamic)" . to_string ( ) )
11211165 }
11221166
1123- updated = true ;
1124- match ( existing_packages. get ( name) , new_distributions. get ( name) ) {
1125- ( Some ( existing_versions) , Some ( new_versions) ) => {
1126- if existing_versions != new_versions {
1127- let existing_versions = existing_versions
1128- . iter ( )
1129- . map ( |version| format_version ( * version) )
1130- . collect :: < Vec < _ > > ( )
1131- . join ( ", " ) ;
1132- let new_versions = new_versions
1133- . iter ( )
1134- . map ( |version| format_version ( * version) )
1135- . collect :: < Vec < _ > > ( )
1136- . join ( ", " ) ;
1137- writeln ! (
1138- printer. stderr( ) ,
1139- "{} {name} {existing_versions} -> {new_versions}" ,
1140- if dry_run { "Update" } else { "Updated" } . green( ) . bold( )
1141- ) ?;
1142- }
1143- }
1144- ( Some ( existing_versions) , None ) => {
1167+ match self {
1168+ Self :: Update ( dry_run, name, existing_versions, new_versions) => {
11451169 let existing_versions = existing_versions
11461170 . iter ( )
11471171 . map ( |version| format_version ( * version) )
11481172 . collect :: < Vec < _ > > ( )
11491173 . join ( ", " ) ;
1150- writeln ! (
1151- printer. stderr( ) ,
1152- "{} {name} {existing_versions}" ,
1153- if dry_run { "Remove" } else { "Removed" } . red( ) . bold( )
1154- ) ?;
1174+ let new_versions = new_versions
1175+ . iter ( )
1176+ . map ( |version| format_version ( * version) )
1177+ . collect :: < Vec < _ > > ( )
1178+ . join ( ", " ) ;
1179+
1180+ write ! (
1181+ f,
1182+ "{} {name} {existing_versions} -> {new_versions}" ,
1183+ if * dry_run { "Update" } else { "Updated" } . green( ) . bold( )
1184+ )
11551185 }
1156- ( None , Some ( new_versions) ) => {
1186+ Self :: Add ( dry_run , name , new_versions) => {
11571187 let new_versions = new_versions
11581188 . iter ( )
11591189 . map ( |version| format_version ( * version) )
11601190 . collect :: < Vec < _ > > ( )
11611191 . join ( ", " ) ;
1162- writeln ! (
1163- printer. stderr( ) ,
1192+
1193+ write ! (
1194+ f,
11641195 "{} {name} {new_versions}" ,
1165- if dry_run { "Add" } else { "Added" } . green( ) . bold( )
1166- ) ? ;
1196+ if * dry_run { "Add" } else { "Added" } . green( ) . bold( )
1197+ )
11671198 }
1168- ( None , None ) => {
1169- unreachable ! ( "The key `{name}` should exist in at least one of the maps" ) ;
1199+ Self :: Remove ( dry_run, name, existing_versions) => {
1200+ let existing_versions = existing_versions
1201+ . iter ( )
1202+ . map ( |version| format_version ( * version) )
1203+ . collect :: < Vec < _ > > ( )
1204+ . join ( ", " ) ;
1205+
1206+ write ! (
1207+ f,
1208+ "{} {name} {existing_versions}" ,
1209+ if * dry_run { "Remove" } else { "Removed" } . red( ) . bold( )
1210+ )
11701211 }
11711212 }
11721213 }
1173-
1174- Ok ( updated)
11751214}
0 commit comments