5
5
use std:: collections:: { HashMap , HashSet } ;
6
6
use std:: fmt:: Write ;
7
7
use std:: future:: ready;
8
+ use std:: num:: NonZero ;
8
9
#[ cfg( unix) ]
9
10
use std:: os:: linux:: fs:: MetadataExt ;
10
11
@@ -16,10 +17,11 @@ use once_cell::sync::OnceCell;
16
17
use progress_bar_derive_macro:: ProgressBar ;
17
18
18
19
use super :: prune:: PruneParameters ;
20
+ use crate :: io:: Pluralize ;
19
21
use crate :: prelude:: * ;
20
22
use crate :: runtime:: makedirs_with_perms;
21
23
use crate :: storage:: fs:: OpenFsRepository ;
22
- use crate :: { encoding, graph, storage, tracking, Error , Result } ;
24
+ use crate :: { encoding, graph, storage, tracking, Digest , Error , Result } ;
23
25
24
26
#[ cfg( test) ]
25
27
#[ path = "./clean_test.rs" ]
43
45
attached : DashSet < encoding:: Digest > ,
44
46
dry_run : bool ,
45
47
must_be_older_than : DateTime < Utc > ,
46
- prune_repeated_tags : bool ,
48
+ prune_repeated_tags : Option < NonZero < u64 > > ,
47
49
prune_params : PruneParameters ,
48
50
remove_proxies_with_no_links : bool ,
49
51
}
@@ -66,7 +68,7 @@ impl<'repo> Cleaner<'repo, SilentCleanReporter> {
66
68
attached : Default :: default ( ) ,
67
69
dry_run : false ,
68
70
must_be_older_than : Utc :: now ( ) ,
69
- prune_repeated_tags : false ,
71
+ prune_repeated_tags : None ,
70
72
prune_params : Default :: default ( ) ,
71
73
remove_proxies_with_no_links : true ,
72
74
}
@@ -154,7 +156,7 @@ where
154
156
155
157
/// When walking the history of a tag, delete older entries
156
158
/// that have the same target as a more recent one.
157
- pub fn with_prune_repeated_tags ( mut self , prune_repeated_tags : bool ) -> Self {
159
+ pub fn with_prune_repeated_tags ( mut self , prune_repeated_tags : Option < NonZero < u64 > > ) -> Self {
158
160
self . prune_repeated_tags = prune_repeated_tags;
159
161
self
160
162
}
@@ -229,11 +231,12 @@ where
229
231
" - {} each item in the tag's history, and for each one:" ,
230
232
"VISIT" . cyan( )
231
233
) ;
232
- if self . prune_repeated_tags || !self . prune_params . is_empty ( ) {
233
- if self . prune_repeated_tags {
234
+ if self . prune_repeated_tags . is_some ( ) || !self . prune_params . is_empty ( ) {
235
+ if let Some ( number) = self . prune_repeated_tags {
236
+ let entries = "entry" . pluralize ( number. get ( ) ) ;
234
237
let _ = writeln ! (
235
238
& mut out,
236
- " - {prune} any entry that has a the same target as a more recent entry" ,
239
+ " - {prune} all but {number} {entries} with the same target as a more recent entry"
237
240
) ;
238
241
}
239
242
let PruneParameters {
@@ -394,14 +397,24 @@ where
394
397
. await ?;
395
398
let mut to_prune = Vec :: with_capacity ( history. len ( ) / 2 ) ;
396
399
let mut to_keep = Vec :: with_capacity ( history. len ( ) / 2 ) ;
397
- let mut seen_targets = std:: collections:: HashSet :: new ( ) ;
400
+ let mut seen_targets: HashMap < Digest , u64 > = std:: collections:: HashMap :: new ( ) ;
398
401
for ( i, tag) in history. into_iter ( ) . enumerate ( ) {
399
402
let spec = tag. to_spec ( i as u64 ) ;
400
403
self . reporter . visit_tag ( & tag) ;
401
- if !seen_targets. insert ( tag. target ) && self . prune_repeated_tags {
402
- to_prune. push ( tag) ;
403
- continue ;
404
- }
404
+ let count = if let Some ( seen_count) = seen_targets. get ( & tag. target ) {
405
+ if let Some ( keep_number) = self . prune_repeated_tags {
406
+ if * seen_count >= keep_number. get ( ) {
407
+ to_prune. push ( tag) ;
408
+ continue ;
409
+ }
410
+ }
411
+ * seen_count + 1
412
+ } else {
413
+ 1
414
+ } ;
415
+
416
+ seen_targets. insert ( tag. target , count) ;
417
+
405
418
if self . prune_params . should_prune ( & spec, & tag) {
406
419
to_prune. push ( tag) ;
407
420
} else {
0 commit comments