@@ -20,6 +20,7 @@ import (
20
20
"context"
21
21
"fmt"
22
22
"io"
23
+ "sync"
23
24
"time"
24
25
25
26
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
@@ -42,185 +43,155 @@ type ImageDetails struct {
42
43
ID string `yaml:"id,omitempty"`
43
44
}
44
45
45
- type detailsErr struct {
46
- details * cachedArtifactDetails
47
- err error
48
- }
49
-
50
46
// RetrieveCachedArtifacts checks to see if artifacts are cached, and returns tags for cached images, otherwise a list of images to be built
51
47
func (c * Cache ) RetrieveCachedArtifacts (ctx context.Context , out io.Writer , artifacts []* latest.Artifact ) ([]* latest.Artifact , []build.Artifact , error ) {
52
48
if ! c .useCache {
53
49
return artifacts , nil , nil
54
50
}
55
51
56
- start := time .Now ()
57
52
color .Default .Fprintln (out , "Checking cache..." )
53
+ start := time .Now ()
58
54
59
- detailsErrs := make ([]chan detailsErr , len (artifacts ))
55
+ wg := sync.WaitGroup {}
56
+ builtImages := make ([]bool , len (artifacts ))
57
+ needToBuildImages := make ([]bool , len (artifacts ))
60
58
61
59
for i := range artifacts {
62
- detailsErrs [i ] = make (chan detailsErr , 1 )
63
-
60
+ wg .Add (1 )
64
61
i := i
65
62
go func () {
66
- details , err := c .retrieveCachedArtifactDetails (ctx , artifacts [i ])
67
- detailsErrs [i ] <- detailsErr {details : details , err : err }
63
+ defer wg .Done ()
64
+ ok , err := c .retrieveCachedArtifact (ctx , out , artifacts [i ])
65
+ if ok {
66
+ builtImages [i ] = true
67
+ return
68
+ }
69
+ if err != nil {
70
+ logrus .Debugf ("error finding cached artifact for %s: %v" , artifacts [i ].ImageName , err )
71
+ }
72
+ color .Default .Fprintf (out , " - %s: " , artifacts [i ].ImageName )
73
+ color .Red .Fprintf (out , "Not Found. Rebuilding.\n " )
74
+ needToBuildImages [i ] = true
68
75
}()
69
76
}
70
77
78
+ wg .Wait ()
79
+
71
80
var (
72
81
needToBuild []* latest.Artifact
73
82
built []build.Artifact
74
83
)
75
84
76
- for i , artifact := range artifacts {
77
- color .Default .Fprintf (out , " - %s: " , artifact .ImageName )
78
-
79
- select {
80
- case <- ctx .Done ():
81
- return nil , nil , context .Canceled
82
-
83
- case d := <- detailsErrs [i ]:
84
- details := d .details
85
- err := d .err
86
- if err != nil || details .needsRebuild {
87
- color .Red .Fprintln (out , "Not found. Rebuilding." )
88
- needToBuild = append (needToBuild , artifact )
89
- continue
90
- }
91
-
92
- color .Green .Fprint (out , "Found" )
93
- if details .needsRetag {
94
- color .Green .Fprint (out , ". Retagging" )
95
- }
96
- if details .needsPush {
97
- color .Green .Fprint (out , ". Pushing." )
98
- }
99
- color .Default .Fprintln (out )
100
-
101
- if details .needsRetag {
102
- if err := c .client .Tag (ctx , details .prebuiltImage , details .hashTag ); err != nil {
103
- return nil , nil , errors .Wrap (err , "retagging image" )
104
- }
105
- }
106
- if details .needsPush {
107
- if _ , err := c .client .Push (ctx , out , details .hashTag ); err != nil {
108
- return nil , nil , errors .Wrap (err , "pushing image" )
109
- }
110
- }
111
-
85
+ for i , imageBuilt := range builtImages {
86
+ if imageBuilt {
112
87
built = append (built , build.Artifact {
113
- ImageName : artifact .ImageName ,
114
- Tag : details . hashTag ,
88
+ ImageName : artifacts [ i ] .ImageName ,
89
+ Tag : HashTag ( artifacts [ i ]) ,
115
90
})
116
91
}
117
92
}
118
93
94
+ for i , imageBuilt := range needToBuildImages {
95
+ if imageBuilt {
96
+ needToBuild = append (needToBuild , artifacts [i ])
97
+ }
98
+ }
99
+
119
100
color .Default .Fprintln (out , "Cache check complete in" , time .Since (start ))
120
101
return needToBuild , built , nil
121
102
}
122
103
123
- type cachedArtifactDetails struct {
124
- needsRebuild bool
125
- needsRetag bool
126
- needsPush bool
127
- prebuiltImage string
128
- hashTag string
129
- }
130
-
131
- func (c * Cache ) retrieveCachedArtifactDetails (ctx context.Context , a * latest.Artifact ) (* cachedArtifactDetails , error ) {
104
+ // retrieveCachedArtifact tries to retrieve a cached artifact.
105
+ // If it cannot, it returns false.
106
+ // If it can, it returns true.
107
+ func (c * Cache ) retrieveCachedArtifact (ctx context.Context , out io.Writer , a * latest.Artifact ) (bool , error ) {
132
108
hash , err := hashForArtifact (ctx , c .builder , a )
133
109
if err != nil {
134
- return nil , errors .Wrapf (err , "getting hash for artifact %s" , a .ImageName )
110
+ return false , errors .Wrapf (err , "getting hash for artifact %s" , a .ImageName )
135
111
}
136
112
a .WorkspaceHash = hash
137
113
imageDetails , cacheHit := c .artifactCache [hash ]
138
114
if ! cacheHit {
139
- return & cachedArtifactDetails {
140
- needsRebuild : true ,
141
- }, nil
115
+ return false , nil
142
116
}
143
- hashTag := HashTag (a )
144
- il , err := c .imageLocation (ctx , imageDetails , hashTag )
145
- if err != nil {
146
- return nil , errors .Wrapf (err , "getting artifact details for %s" , a .ImageName )
117
+ if c .localCluster && ! c .pushImages {
118
+ return c .artifactExistsLocally (ctx , out , a , imageDetails )
147
119
}
148
- return & cachedArtifactDetails {
149
- needsRebuild : needsRebuild (il , c .localCluster ),
150
- needsRetag : needsRetag (il ),
151
- needsPush : needsPush (il , c .localCluster , c .pushImages ),
152
- prebuiltImage : il .prebuiltImage ,
153
- hashTag : hashTag ,
154
- }, nil
155
- }
156
-
157
- // imageLocation holds information about where the image currently is
158
- type imageLocation struct {
159
- existsRemotely bool
160
- existsLocally bool
161
- prebuiltImage string
120
+ return c .artifactExistsRemotely (ctx , out , a , imageDetails )
162
121
}
163
122
164
- func (c * Cache ) imageLocation (ctx context.Context , imageDetails ImageDetails , tag string ) (* imageLocation , error ) {
165
- // Check if tagged image exists remotely with the same digest
166
- existsRemotely := imgExistsRemotely (tag , imageDetails .Digest , c .insecureRegistries )
167
- existsLocally := false
168
- if c .client != nil {
169
- // See if this image exists in the local daemon
170
- if c .client .ImageExists (ctx , tag ) {
171
- existsLocally = true
172
- }
173
- }
174
- if existsLocally {
175
- return & imageLocation {
176
- existsLocally : existsLocally ,
177
- existsRemotely : existsRemotely ,
178
- prebuiltImage : tag ,
179
- }, nil
123
+ // artifactExistsLocally assumes the artifact must exist locally.
124
+ // This is called when using a local cluster and push:false.
125
+ // 1. Check if image exists locally
126
+ // 2. If not, check if same digest exists locally. If it does, retag.
127
+ // 3. If not, rebuild
128
+ // It returns true if the artifact exists locally, and false if not.
129
+ func (c * Cache ) artifactExistsLocally (ctx context.Context , out io.Writer , a * latest.Artifact , imageDetails ImageDetails ) (bool , error ) {
130
+ hashTag := HashTag (a )
131
+ if c .client .ImageExists (ctx , hashTag ) {
132
+ color .Default .Fprintf (out , " - %s: " , a .ImageName )
133
+ color .Green .Fprintf (out , "Found\n " )
134
+ return true , nil
180
135
}
181
136
// Check for a local image with the same digest as the image we want to build
182
137
prebuiltImage , err := c .retrievePrebuiltImage (imageDetails )
183
138
if err != nil {
184
- return nil , errors .Wrapf (err , "getting prebuilt image" )
185
- }
186
- return & imageLocation {
187
- existsRemotely : existsRemotely ,
188
- existsLocally : existsLocally ,
189
- prebuiltImage : prebuiltImage ,
190
- }, nil
191
- }
192
-
193
- func needsRebuild (d * imageLocation , localCluster bool ) bool {
194
- // If using local cluster, rebuild if all of the following are true:
195
- // 1. does not exist locally
196
- // 2. can't retag a prebuilt image
197
- if localCluster {
198
- return ! d .existsLocally && d .prebuiltImage == ""
139
+ return false , errors .Wrapf (err , "getting prebuilt image" )
140
+ }
141
+ // If prebuilt image exists, tag it. Otherwise, return false, as artifact doesn't exist locally.
142
+ if prebuiltImage != "" {
143
+ color .Default .Fprintf (out , " - %s: " , a .ImageName )
144
+ color .Green .Fprintf (out , "Found. Retagging.\n " )
145
+ if err := c .client .Tag (ctx , prebuiltImage , hashTag ); err != nil {
146
+ return false , errors .Wrap (err , "retagging image" )
147
+ }
148
+ return true , nil
199
149
}
200
- // If using remote cluster, only rebuild image if all of the following are true:
201
- // 1. does not exist locally
202
- // 2. does not exist remotely
203
- // 3. can't retag a prebuilt image
204
- return ! d .existsLocally && ! d .existsRemotely && d .prebuiltImage == ""
150
+ return false , nil
205
151
}
206
152
207
- func needsPush (d * imageLocation , localCluster , push bool ) bool {
208
- // If using local cluster...
209
- if localCluster {
210
- // ... only push if specified and image does not exist remotely
211
- return push && ! d .existsRemotely
153
+ // artifactExistsRemotely assumes the artifact must exist locally.
154
+ // this is used when running a remote cluster, or when push:true
155
+ // 1. Check if image exists remotely.
156
+ // 2. If not, check if same digest exists locally. If it does, retag and repush.
157
+ // 3. If not, rebuild.
158
+ // It returns true if the artifact exists remotely, and false if not.
159
+ func (c * Cache ) artifactExistsRemotely (ctx context.Context , out io.Writer , a * latest.Artifact , imageDetails ImageDetails ) (bool , error ) {
160
+ hashTag := HashTag (a )
161
+ if imgExistsRemotely (hashTag , imageDetails .Digest , c .insecureRegistries ) {
162
+ color .Default .Fprintf (out , " - %s: " , a .ImageName )
163
+ color .Green .Fprintf (out , "Found\n " )
164
+ return true , nil
165
+ }
166
+
167
+ // Check if image exists locally.
168
+ if c .client .ImageExists (ctx , hashTag ) {
169
+ color .Default .Fprintf (out , " - %s: " , a .ImageName )
170
+ color .Green .Fprintf (out , "Found Locally. Pushing.\n " )
171
+ if _ , err := c .client .Push (ctx , out , hashTag ); err != nil {
172
+ return false , errors .Wrap (err , "retagging image" )
173
+ }
174
+ return true , nil
212
175
}
213
- // If using remote cluster, push if image does not exist remotely
214
- return ! d .existsRemotely
215
- }
216
176
217
- func needsRetag (d * imageLocation ) bool {
218
- // Don't need a retag if image already exists locally
219
- if d .existsLocally {
220
- return false
177
+ // Check for a local image with the same digest as the image we want to build
178
+ prebuiltImage , err := c .retrievePrebuiltImage (imageDetails )
179
+ if err != nil {
180
+ return false , errors .Wrapf (err , "getting prebuilt image" )
181
+ }
182
+ // If prebuilt image exists, tag it and push it. Otherwise, return false, as artifact doesn't exist locally.
183
+ if prebuiltImage != "" {
184
+ color .Default .Fprintf (out , " - %s: " , a .ImageName )
185
+ color .Green .Fprintf (out , "Found Locally. Retagging and Pushing.\n " )
186
+ if err := c .client .Tag (ctx , prebuiltImage , hashTag ); err != nil {
187
+ return false , errors .Wrap (err , "retagging image" )
188
+ }
189
+ if _ , err := c .client .Push (ctx , out , hashTag ); err != nil {
190
+ return false , errors .Wrap (err , "retagging image" )
191
+ }
192
+ return true , nil
221
193
}
222
- // If a prebuilt image is found locally, retag the image
223
- return d .prebuiltImage != ""
194
+ return false , nil
224
195
}
225
196
226
197
func (c * Cache ) retrievePrebuiltImage (details ImageDetails ) (string , error ) {
0 commit comments