1
1
package main
2
2
3
3
import (
4
+ "crypto/sha256"
5
+ "fmt"
4
6
"os"
5
7
"path/filepath"
6
8
9
+ "github.com/lima-vm/lima/pkg/limayaml"
10
+ "github.com/lima-vm/lima/pkg/store"
11
+ "github.com/lima-vm/lima/pkg/templatestore"
7
12
"github.com/sirupsen/logrus"
8
13
"github.com/spf13/cobra"
9
14
)
@@ -17,15 +22,115 @@ func newPruneCommand() *cobra.Command {
17
22
ValidArgsFunction : cobra .NoFileCompletions ,
18
23
GroupID : advancedCommand ,
19
24
}
25
+ pruneCommand .Flags ().Bool ("keep-referred" , false , "Keep objects that are referred by some instances or templates" )
20
26
return pruneCommand
21
27
}
22
28
23
- func pruneAction (_ * cobra.Command , _ []string ) error {
29
+ func pruneAction (cmd * cobra.Command , _ []string ) error {
30
+ keepReferred , err := cmd .Flags ().GetBool ("keep-referred" )
31
+ if err != nil {
32
+ return err
33
+ }
24
34
ucd , err := os .UserCacheDir ()
25
35
if err != nil {
26
36
return err
27
37
}
28
38
cacheDir := filepath .Join (ucd , "lima" )
29
39
logrus .Infof ("Pruning %q" , cacheDir )
30
- return os .RemoveAll (cacheDir )
40
+ if ! keepReferred {
41
+ return os .RemoveAll (cacheDir )
42
+ }
43
+
44
+ // Prune downloads that are not used by any instances or templates
45
+ downloadDir := filepath .Join (cacheDir , "download" , "by-url-sha256" )
46
+ _ , err = os .Stat (downloadDir )
47
+ if err != nil {
48
+ if os .IsNotExist (err ) {
49
+ return nil
50
+ }
51
+ return err
52
+ }
53
+ cacheEntries , err := os .ReadDir (downloadDir )
54
+ if err != nil {
55
+ return err
56
+ }
57
+ knownLocations , err := knownLocations ()
58
+ if err != nil {
59
+ return err
60
+ }
61
+ for _ , entry := range cacheEntries {
62
+ if file , exists := knownLocations [entry .Name ()]; exists {
63
+ logrus .Debugf ("Keep %q caching %q" , entry .Name (), file .Location )
64
+ } else {
65
+ logrus .Debug ("Deleting " , entry .Name ())
66
+ if err := os .RemoveAll (filepath .Join (downloadDir , entry .Name ())); err != nil {
67
+ logrus .Warnf ("Failed to delete %q: %v" , entry .Name (), err )
68
+ return err
69
+ }
70
+ }
71
+ }
72
+ return nil
73
+ }
74
+
75
+ func knownLocations () (map [string ]limayaml.File , error ) {
76
+ locations := make (map [string ]limayaml.File )
77
+
78
+ // Collect locations from instances
79
+ instances , err := store .Instances ()
80
+ if err != nil {
81
+ return nil , err
82
+ }
83
+ for _ , instanceName := range instances {
84
+ instance , err := store .Inspect (instanceName )
85
+ if err != nil {
86
+ return nil , err
87
+ }
88
+ for k , v := range locationsFromLimaYAML (instance .Config ) {
89
+ locations [k ] = v
90
+ }
91
+ }
92
+
93
+ // Collect locations from templates
94
+ templates , err := templatestore .Templates ()
95
+ if err != nil {
96
+ return nil , err
97
+ }
98
+ for _ , t := range templates {
99
+ b , err := templatestore .Read (t .Name )
100
+ if err != nil {
101
+ return nil , err
102
+ }
103
+ y , err := limayaml .Load (b , t .Name )
104
+ if err != nil {
105
+ return nil , err
106
+ }
107
+ for k , v := range locationsFromLimaYAML (y ) {
108
+ locations [k ] = v
109
+ }
110
+ }
111
+ return locations , nil
112
+ }
113
+
114
+ func locationsFromLimaYAML (y * limayaml.LimaYAML ) map [string ]limayaml.File {
115
+ locations := make (map [string ]limayaml.File )
116
+ for _ , f := range y .Images {
117
+ locations [sha256OfURL (f .Location )] = f .File
118
+ if f .Kernel != nil {
119
+ locations [sha256OfURL (f .Kernel .Location )] = f .Kernel .File
120
+ }
121
+ if f .Initrd != nil {
122
+ locations [sha256OfURL (f .Initrd .Location )] = * f .Initrd
123
+ }
124
+ }
125
+ for _ , f := range y .Containerd .Archives {
126
+ locations [sha256OfURL (f .Location )] = f
127
+ }
128
+ for _ , f := range y .Firmware .Images {
129
+ locations [sha256OfURL (f .Location )] = f .File
130
+ }
131
+ return locations
132
+ }
133
+
134
+ func sha256OfURL (url string ) string {
135
+ return fmt .Sprintf ("%x" , sha256 .Sum256 ([]byte (url )))
31
136
}
0 commit comments