@@ -33,6 +33,8 @@ import (
33
33
"github.com/docker/compose-cli/api/progress"
34
34
)
35
35
36
+ type downOp func () error
37
+
36
38
func (s * composeService ) Down (ctx context.Context , projectName string , options compose.DownOptions ) error {
37
39
w := progress .ContextWriter (ctx )
38
40
resourceToRemove := false
@@ -73,37 +75,76 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
73
75
}
74
76
}
75
77
76
- networks , err := s .apiClient . NetworkList (ctx , moby. NetworkListOptions { Filters : filters . NewArgs ( projectFilter ( projectName ))} )
78
+ ops , err := s .ensureNetwoksDown (ctx , projectName )
77
79
if err != nil {
78
80
return err
79
81
}
80
82
81
- eg , _ := errgroup .WithContext (ctx )
82
- for _ , n := range networks {
83
- resourceToRemove = true
84
- networkID := n .ID
85
- networkName := n .Name
86
- eg .Go (func () error {
87
- return s .ensureNetworkDown (ctx , networkID , networkName )
88
- })
83
+ if options .Images != "" {
84
+ ops = append (ops , s .ensureImagesDown (ctx , projectName , options , w )... )
89
85
}
90
86
91
- if options .Images != "" {
92
- for image := range s .getServiceImages (options , projectName ) {
93
- image := image
94
- eg .Go (func () error {
95
- resourceToRemove = true
96
- return s .removeImage (ctx , image , w )
97
- })
87
+ if options .Volumes {
88
+ rm , err := s .ensureVolumesDown (ctx , projectName , w )
89
+ if err != nil {
90
+ return err
98
91
}
92
+ ops = append (ops , rm ... )
99
93
}
100
94
101
- if ! resourceToRemove {
95
+ if ! resourceToRemove && len ( ops ) == 0 {
102
96
w .Event (progress .NewEvent (projectName , progress .Done , "Warning: No resource found to remove" ))
103
97
}
98
+
99
+ eg , _ := errgroup .WithContext (ctx )
100
+ for _ , op := range ops {
101
+ eg .Go (op )
102
+ }
104
103
return eg .Wait ()
105
104
}
106
105
106
+ func (s * composeService ) ensureVolumesDown (ctx context.Context , projectName string , w progress.Writer ) ([]downOp , error ) {
107
+ var ops []downOp
108
+ volumes , err := s .apiClient .VolumeList (ctx , filters .NewArgs (projectFilter (projectName )))
109
+ if err != nil {
110
+ return ops , err
111
+ }
112
+ for _ , vol := range volumes .Volumes {
113
+ id := vol .Name
114
+ ops = append (ops , func () error {
115
+ return s .removeVolume (ctx , id , w )
116
+ })
117
+ }
118
+ return ops , nil
119
+ }
120
+
121
+ func (s * composeService ) ensureImagesDown (ctx context.Context , projectName string , options compose.DownOptions , w progress.Writer ) []downOp {
122
+ var ops []downOp
123
+ for image := range s .getServiceImages (options , projectName ) {
124
+ image := image
125
+ ops = append (ops , func () error {
126
+ return s .removeImage (ctx , image , w )
127
+ })
128
+ }
129
+ return ops
130
+ }
131
+
132
+ func (s * composeService ) ensureNetwoksDown (ctx context.Context , projectName string ) ([]downOp , error ) {
133
+ var ops []downOp
134
+ networks , err := s .apiClient .NetworkList (ctx , moby.NetworkListOptions {Filters : filters .NewArgs (projectFilter (projectName ))})
135
+ if err != nil {
136
+ return ops , err
137
+ }
138
+ for _ , n := range networks {
139
+ networkID := n .ID
140
+ networkName := n .Name
141
+ ops = append (ops , func () error {
142
+ return s .removeNetwork (ctx , networkID , networkName )
143
+ })
144
+ }
145
+ return ops , nil
146
+ }
147
+
107
148
func (s * composeService ) getServiceImages (options compose.DownOptions , projectName string ) map [string ]struct {} {
108
149
images := map [string ]struct {}{}
109
150
for _ , service := range options .Project .Services {
@@ -134,6 +175,21 @@ func (s *composeService) removeImage(ctx context.Context, image string, w progre
134
175
return err
135
176
}
136
177
178
+ func (s * composeService ) removeVolume (ctx context.Context , id string , w progress.Writer ) error {
179
+ resource := fmt .Sprintf ("Volume %s" , id )
180
+ w .Event (progress .NewEvent (resource , progress .Working , "Removing" ))
181
+ err := s .apiClient .VolumeRemove (ctx , id , true )
182
+ if err == nil {
183
+ w .Event (progress .NewEvent (resource , progress .Done , "Removed" ))
184
+ return nil
185
+ }
186
+ if errdefs .IsNotFound (err ) {
187
+ w .Event (progress .NewEvent (resource , progress .Done , "Warning: No resource found to remove" ))
188
+ return nil
189
+ }
190
+ return err
191
+ }
192
+
137
193
func (s * composeService ) stopContainers (ctx context.Context , w progress.Writer , containers []moby.Container , timeout * time.Duration ) error {
138
194
for _ , container := range containers {
139
195
toStop := container
0 commit comments