@@ -17,6 +17,7 @@ import (
17
17
"log"
18
18
"os"
19
19
"os/exec"
20
+ "path"
20
21
"path/filepath"
21
22
"runtime"
22
23
"strings"
@@ -27,6 +28,7 @@ import (
27
28
v1 "github.com/google/go-containerregistry/pkg/v1"
28
29
"github.com/google/go-containerregistry/pkg/v1/daemon"
29
30
"github.com/google/go-containerregistry/pkg/v1/empty"
31
+ "github.com/google/go-containerregistry/pkg/v1/layout"
30
32
"github.com/google/go-containerregistry/pkg/v1/mutate"
31
33
"github.com/google/go-containerregistry/pkg/v1/remote"
32
34
"github.com/google/go-containerregistry/pkg/v1/tarball"
@@ -79,6 +81,7 @@ type buildParams struct {
79
81
staticFiles map [string ]string
80
82
imageRefs []name.Tag
81
83
publish bool
84
+ outPath string
82
85
ldflags string
83
86
gotags string
84
87
target string
@@ -96,6 +99,7 @@ func main() {
96
99
ldflagsArg = flag .String ("ldflags" , "" , "the --ldflags value to pass to go" )
97
100
gotags = flag .String ("gotags" , "" , "the --tags value to pass to go" )
98
101
push = flag .Bool ("push" , false , "publish the image" )
102
+ outPath = flag .String ("out" , "" , "writes image(s) to a given folder" )
99
103
target = flag .String ("target" , "" , "build for a specific env (options: flyio, local)" )
100
104
verbose = flag .Bool ("v" , false , "verbose build output" )
101
105
annotations = flag .String ("annotations" , "" , `OCI image annotations https://github.com/opencontainers/image-spec/blob/main/annotations.md.
@@ -140,6 +144,7 @@ func main() {
140
144
staticFiles : staticFiles ,
141
145
imageRefs : refs ,
142
146
publish : * push ,
147
+ outPath : * outPath ,
143
148
ldflags : * ldflagsArg ,
144
149
gotags : * gotags ,
145
150
target : * target ,
@@ -198,6 +203,34 @@ func verifyPlatform(p v1.Platform, target string) error {
198
203
return nil
199
204
}
200
205
206
+ func createOutDirectory (path string ) error {
207
+ fi , err := os .Stat (path )
208
+ if err != nil {
209
+ if ! os .IsNotExist (err ) {
210
+ return fmt .Errorf ("checking out path: %w" , err )
211
+ }
212
+ }
213
+ if fi != nil && ! fi .IsDir () {
214
+ return fmt .Errorf ("out must be a directory: %s" , path )
215
+ }
216
+ if err = os .MkdirAll (path , 0755 ); err != nil {
217
+ return fmt .Errorf ("creating out directory: %w" , err )
218
+ }
219
+ return nil
220
+ }
221
+
222
+ func writeImageToFile (img v1.Image , imgRef name.Reference , p string ) error {
223
+ err := createOutDirectory (p )
224
+ if err != nil {
225
+ return err
226
+ }
227
+ if err := tarball .WriteToFile (path .Join (p , "image.tar" ), imgRef , img ); err != nil {
228
+ return err
229
+ }
230
+
231
+ return nil
232
+ }
233
+
201
234
func fetchAndBuild (bp * buildParams ) error {
202
235
ctx := context .Background ()
203
236
logf := log .Printf
@@ -243,25 +276,30 @@ func fetchAndBuild(bp *buildParams) error {
243
276
if err != nil {
244
277
return err
245
278
}
246
- if ! bp .publish {
247
- logf ("not pushing" )
248
- return nil
249
- }
250
279
251
- img = mutate .Annotations (img , bp .annotations ).(v1.Image ) // OCI annotations
280
+ switch {
281
+ case bp .publish :
282
+ img = mutate .Annotations (img , bp .annotations ).(v1.Image ) // OCI annotations
252
283
253
- for _ , r := range bp .imageRefs {
254
- if bp .target == "local" {
255
- if err := loadLocalImage (logf , r , img ); err != nil {
284
+ for _ , r := range bp .imageRefs {
285
+ if bp .target == "local" {
286
+ if err := loadLocalImage (logf , r , img ); err != nil {
287
+ return err
288
+ }
289
+ continue
290
+ }
291
+ logf ("pushing to %v" , r )
292
+ if err := remote .Write (r , img , remoteOpts ... ); err != nil {
256
293
return err
257
294
}
258
- continue
259
- }
260
- logf ("pushing to %v" , r )
261
- if err := remote .Write (r , img , remoteOpts ... ); err != nil {
262
- return err
263
295
}
296
+ return nil
297
+
298
+ case bp .outPath != "" :
299
+ return writeImageToFile (img , bp .imageRefs [0 ], bp .outPath )
264
300
}
301
+ logf ("not pushing or writing to file" )
302
+
265
303
return nil
266
304
case types .OCIImageIndex , types .DockerManifestList :
267
305
// baseRef is a multi-platform index, rest of the method handles this.
@@ -336,23 +374,28 @@ func fetchAndBuild(bp *buildParams) error {
336
374
return err
337
375
}
338
376
logf ("image digest: %v" , d )
339
- if ! bp .publish {
340
- logf ("not pushing" )
341
- return nil
342
- }
343
377
344
- for _ , r := range bp .imageRefs {
345
- if bp .target == "local" {
346
- if err := loadLocalImage (logf , r , img ); err != nil {
378
+ switch {
379
+ case bp .publish :
380
+ for _ , r := range bp .imageRefs {
381
+ if bp .target == "local" {
382
+ if err := loadLocalImage (logf , r , img ); err != nil {
383
+ return err
384
+ }
385
+ continue
386
+ }
387
+ logf ("pushing to %v" , r )
388
+ if err := remote .Write (r , img , remoteOpts ... ); err != nil {
347
389
return err
348
390
}
349
- continue
350
- }
351
- logf ("pushing to %v" , r )
352
- if err := remote .Write (r , img , remoteOpts ... ); err != nil {
353
- return err
354
391
}
392
+ return nil
393
+
394
+ case bp .outPath != "" :
395
+ return writeImageToFile (img , bp .imageRefs [0 ], bp .outPath )
355
396
}
397
+ logf ("not pushing or writing to file" )
398
+
356
399
return nil
357
400
}
358
401
if bp .target == "local" {
@@ -371,17 +414,30 @@ func fetchAndBuild(bp *buildParams) error {
371
414
idx = mutate .Annotations (idx , bp .annotations ).(v1.ImageIndex )
372
415
373
416
logf ("index digest: %v" , d )
374
- if ! bp .publish {
375
- logf ("not pushing" )
417
+
418
+ switch {
419
+ case bp .publish :
420
+ for _ , r := range bp .imageRefs {
421
+ logf ("pushing to %v" , r )
422
+ if err := remote .WriteIndex (r , idx , remoteOpts ... ); err != nil {
423
+ return err
424
+ }
425
+ }
426
+
376
427
return nil
377
- }
378
428
379
- for _ , r := range bp .imageRefs {
380
- logf ("pushing to %v" , r )
381
- if err := remote .WriteIndex (r , idx , remoteOpts ... ); err != nil {
429
+ case bp .outPath != "" :
430
+ err := createOutDirectory (bp .outPath )
431
+ if err != nil {
432
+ return err
433
+ }
434
+ if _ , err := layout .Write (bp .outPath , idx ); err != nil {
382
435
return err
383
436
}
437
+
438
+ return nil
384
439
}
440
+ logf ("not pushing or writing to file" )
385
441
386
442
return nil
387
443
}
0 commit comments