-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
127 lines (108 loc) · 3.08 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"sync"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/eiannone/keyboard"
"github.com/moby/moby/client"
)
func main() {
ctx := context.Background()
cli, err := client.NewEnvClient()
if err != nil {
log.Fatalf("Error creating docker client: %v\n", err)
}
noDanglingfilters := filters.NewArgs()
noDanglingfilters.Add("dangling", "false")
images, err := cli.ImageList(ctx, types.ImageListOptions{Filters: noDanglingfilters})
if err != nil {
log.Fatalf("Error in image list: %v\n", err)
}
if len(images) == 0 {
fmt.Println("No available docker images to remove. Exiting...")
os.Exit(0)
}
if err := keyboard.Open(); err != nil {
log.Fatalf("Error in opening terminal in raw mode: %v\n", err)
}
defer closeKeyboard()
var wg sync.WaitGroup
for _, image := range images {
for _, tag := range image.RepoTags {
fmt.Printf("Delete: %s (y/n) ", tag)
input, key, err := keyboard.GetKey()
if err != nil {
log.Fatalf("Error in scanning user input: %v\n", err)
}
if key == keyboard.KeyCtrlC {
closeKeyboard()
os.Exit(0)
}
if input == 'y' || input == 'Y' {
fmt.Printf("\u2705")
wg.Add(1)
go removeDockerImage(cli, ctx, tag, &wg)
} else {
fmt.Printf("\u274C")
}
fmt.Println()
}
}
// Check and remove dangling images.
danglingFilters := filters.NewArgs()
danglingFilters.Add("dangling", "true")
images, err = cli.ImageList(ctx, types.ImageListOptions{Filters: danglingFilters})
if err != nil {
log.Fatalf("Error in listing dangling images: %v\n", err)
}
if len(images) > 0 {
removeDanglingImages(images)
}
wg.Wait()
}
func removeDanglingImages(images []types.ImageSummary) {
fmt.Print("Delete: dangling <none>:<none> images (y/n) ")
input, key, err := keyboard.GetKey()
if err != nil {
log.Fatalf("Error in scanning user input: %v\n", err)
}
if key == keyboard.KeyCtrlC {
closeKeyboard()
os.Exit(0)
}
if input == 'y' || input == 'Y' {
fmt.Printf("\u2705")
for _, image := range images {
cmd := exec.Command("docker", "rmi", "--force", fmt.Sprintf("%s", image.ID))
if err := cmd.Run(); err != nil {
closeKeyboard()
log.Fatalf("Error in removing dangling image: %v\n", err)
}
}
} else {
fmt.Printf("\u274C")
}
fmt.Println()
}
func removeDockerImage(cli *client.Client, ctx context.Context, tag string, wg *sync.WaitGroup) {
// docker client SDK only has an {ImageRemove} method, and no method for untagging images.
// We don't want to forcefully remove an image, if it has multiple tags.
// Rather we would just like to untag the tag. If it's the only tag left, we will remove the image.
// exec docker CLI due to lack of support from docker client SDK.
cmd := exec.Command("docker", "rmi", "--force", fmt.Sprintf("%s", tag))
if err := cmd.Run(); err != nil {
closeKeyboard()
log.Fatalf("Error in removing docker image: %v\n", err)
}
wg.Done()
}
func closeKeyboard() {
if err := keyboard.Close(); err != nil {
log.Fatalf("Error in closing terminal in raw mode: %v\n", err)
}
}