@@ -10,15 +10,18 @@ use std::{
10
10
11
11
use itertools:: Itertools ;
12
12
use thiserror:: Error ;
13
- use tui:: pretty:: print_to_columns;
13
+ use tui:: {
14
+ dialoguer:: { theme:: ColorfulTheme , Confirm } ,
15
+ pretty:: print_to_columns,
16
+ } ;
14
17
15
18
use crate :: { client:: cache, db, environment, package, state, Installation , State } ;
16
19
17
20
/// The prune strategy for removing old states
18
21
#[ derive( Debug , Clone , Copy ) ]
19
22
pub enum Strategy {
20
23
/// Keep the most recent N states, remove the rest
21
- KeepRecent ( u64 ) ,
24
+ KeepRecent { keep : u64 , include_newer : bool } ,
22
25
/// Removes a specific state
23
26
Remove ( state:: Id ) ,
24
27
}
@@ -31,6 +34,7 @@ pub fn prune(
31
34
install_db : & db:: meta:: Database ,
32
35
layout_db : & db:: layout:: Database ,
33
36
installation : & Installation ,
37
+ yes : bool ,
34
38
) -> Result < ( ) , Error > {
35
39
// Only prune if the moss root has an active state (otherwise
36
40
// it's probably borked or not setup yet)
@@ -42,20 +46,26 @@ pub fn prune(
42
46
43
47
// Find each state we need to remove
44
48
let removal_ids = match strategy {
45
- Strategy :: KeepRecent ( keep) => {
46
- // Filter for all states before the current
47
- let old_states = state_ids
49
+ Strategy :: KeepRecent { keep, include_newer } => {
50
+ // Filter for all removal candidates
51
+ let candidates = state_ids
48
52
. iter ( )
49
- . filter ( |( id, _) | * id < current_state)
53
+ . filter ( |( id, _) | {
54
+ if include_newer {
55
+ * id != current_state
56
+ } else {
57
+ * id < current_state
58
+ }
59
+ } )
50
60
. collect :: < Vec < _ > > ( ) ;
51
- // Deduct current state from num to keep
52
- let old_limit = ( keep as usize ) . saturating_sub ( 1 ) ;
61
+ // Deduct current state from num candidates to keep
62
+ let candidate_limit = ( keep as usize ) . saturating_sub ( 1 ) ;
53
63
54
- // Calculate how many old states over the limit we are
55
- let num_to_remove = old_states . len ( ) . saturating_sub ( old_limit ) ;
64
+ // Calculate how many candidate states over the limit we are
65
+ let num_to_remove = candidates . len ( ) . saturating_sub ( candidate_limit ) ;
56
66
57
67
// Sort ascending and assign first `num_to_remove` as `Status::Remove`
58
- old_states
68
+ candidates
59
69
. into_iter ( )
60
70
. sorted_by_key ( |( _, created) | * created)
61
71
. enumerate ( )
@@ -118,6 +128,18 @@ pub fn prune(
118
128
print_to_columns ( & removals. iter ( ) . map ( state:: ColumnDisplay ) . collect :: < Vec < _ > > ( ) ) ;
119
129
println ! ( ) ;
120
130
131
+ let result = if yes {
132
+ true
133
+ } else {
134
+ Confirm :: with_theme ( & ColorfulTheme :: default ( ) )
135
+ . with_prompt ( " Do you wish to continue? " )
136
+ . default ( false )
137
+ . interact ( ) ?
138
+ } ;
139
+ if !result {
140
+ return Err ( Error :: Cancelled ) ;
141
+ }
142
+
121
143
// Prune these states / packages from all dbs
122
144
prune_databases ( & removals, & package_removals, state_db, install_db, layout_db) ?;
123
145
@@ -295,6 +317,8 @@ fn remove_empty_dirs(starting: &Path, root: &Path) -> Result<(), io::Error> {
295
317
296
318
#[ derive( Debug , Error ) ]
297
319
pub enum Error {
320
+ #[ error( "cancelled" ) ]
321
+ Cancelled ,
298
322
#[ error( "no active state found" ) ]
299
323
NoActiveState ,
300
324
#[ error( "cannot prune the currently active state" ) ]
@@ -307,4 +331,6 @@ pub enum Error {
307
331
StateDB ( #[ from] db:: state:: Error ) ,
308
332
#[ error( "io" ) ]
309
333
Io ( #[ from] io:: Error ) ,
334
+ #[ error( "string processing" ) ]
335
+ Dialog ( #[ from] tui:: dialoguer:: Error ) ,
310
336
}
0 commit comments