@@ -8,7 +8,7 @@ use chrono::Utc;
88use color_eyre:: Result ;
99use humantime:: Duration as HumantimeDuration ;
1010use indicatif:: ProgressStyle ;
11- use std:: collections:: HashMap ;
11+ use std:: collections:: { HashMap , HashSet } ;
1212use std:: sync:: Arc ;
1313use std:: time:: Duration ;
1414use tokio:: task:: JoinSet ;
@@ -287,16 +287,104 @@ pub async fn select_package_versions(
287287 ) ;
288288 }
289289
290- let mut package_version_map = HashMap :: new ( ) ;
290+ let mut all_package_versions = vec ! [ ] ;
291+ let mut fetch_digest_set = JoinSet :: new ( ) ;
291292
292293 debug ! ( "Fetching package versions" ) ;
294+
293295 while let Some ( r) = set. join_next ( ) . await {
294296 // Get all the package versions for a package
295297 let ( package_name, mut package_versions) = r??;
296298
299+ // Queue fetching of digests for each tag
300+ for package_version in & package_versions. tagged {
301+ for tag in & package_version. metadata . container . tags {
302+ fetch_digest_set. spawn ( client. fetch_image_manifest ( package_name. clone ( ) , tag. clone ( ) ) ) ;
303+ }
304+ }
305+
306+ all_package_versions. push ( ( package_name, package_versions) ) ;
307+ }
308+
309+ debug ! ( "Fetching package versions" ) ;
310+ let mut digests = HashSet :: new ( ) ;
311+ let mut digest_tag = HashMap :: new ( ) ;
312+
313+ while let Some ( r) = fetch_digest_set. join_next ( ) . await {
314+ // Get all the digests for the package
315+ let ( package_name, tag, package_digests) = r??;
316+
317+ if package_digests. is_empty ( ) {
318+ debug ! (
319+ package_name = package_name,
320+ "Found {} associated digests for \x1b [34m{package_name}\x1b [0m:\x1b [32m{tag}\x1b [0m" ,
321+ package_digests. len( )
322+ ) ;
323+ } else {
324+ info ! (
325+ package_name = package_name,
326+ "Found {} associated digests for \x1b [34m{package_name}\x1b [0m:\x1b [32m{tag}\x1b [0m" ,
327+ package_digests. len( )
328+ ) ;
329+ }
330+
331+ digests. extend ( package_digests. clone ( ) ) ;
332+ for digest in package_digests. into_iter ( ) {
333+ digest_tag. insert ( digest, format ! ( "\x1b [34m{package_name}\x1b [0m:\x1b [32m{tag}\x1b [0m" ) ) ;
334+ }
335+ }
336+
337+ let mut package_version_map = HashMap :: new ( ) ;
338+
339+ for ( package_name, mut package_versions) in all_package_versions {
340+ package_versions. untagged = package_versions
341+ . untagged
342+ . into_iter ( )
343+ . filter_map ( |package_version| {
344+ if digests. contains ( & package_version. name ) {
345+ let x: String = package_version. name . clone ( ) ;
346+ let association: & String = digest_tag. get ( & x as & str ) . unwrap ( ) ;
347+ debug ! (
348+ "Skipping deletion of {} because it's associated with {association}" ,
349+ package_version. name
350+ ) ;
351+ None
352+ } else {
353+ Some ( package_version)
354+ }
355+ } )
356+ . collect ( ) ;
357+ let count_before = package_versions. tagged . len ( ) ;
358+ package_versions. tagged = package_versions
359+ . tagged
360+ . into_iter ( )
361+ . filter ( |package_version| {
362+ if digests. contains ( & package_version. name ) {
363+ let association = digest_tag. get ( & * ( package_version. name ) ) . unwrap ( ) ;
364+ debug ! (
365+ "Skipping deletion of {} because it's associated with {association}" ,
366+ package_version. name
367+ ) ;
368+ false
369+ } else {
370+ true
371+ }
372+ } )
373+ . collect ( ) ;
374+
375+ let adjusted_keep_n_most_recent =
376+ if keep_n_most_recent as i64 - ( count_before as i64 - package_versions. tagged . len ( ) as i64 ) < 0 {
377+ 0
378+ } else {
379+ keep_n_most_recent as i64 - ( count_before as i64 - package_versions. tagged . len ( ) as i64 )
380+ } ;
381+
297382 // Keep n package versions per package, if specified
298- package_versions. tagged =
299- handle_keep_n_most_recent ( package_versions. tagged , keep_n_most_recent, timestamp_to_use) ;
383+ package_versions. tagged = handle_keep_n_most_recent (
384+ package_versions. tagged ,
385+ adjusted_keep_n_most_recent as u32 ,
386+ timestamp_to_use,
387+ ) ;
300388
301389 info ! (
302390 package_name = package_name,
0 commit comments