Skip to content

Commit 975889b

Browse files
committed
mkctr: add flag to save image/images to disk
This commit adds a new flag, --out-path which will allow the user to write the image to disk; if building a single image, e.g. with --target local, a tar is created at the out-path. if building a multi arch image, then a directorty is created with the images and oci manifest. Signed-off-by: Kristoffer Dalby <[email protected]>
1 parent 5497735 commit 975889b

File tree

1 file changed

+74
-31
lines changed

1 file changed

+74
-31
lines changed

mkctr.go

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
v1 "github.com/google/go-containerregistry/pkg/v1"
2828
"github.com/google/go-containerregistry/pkg/v1/daemon"
2929
"github.com/google/go-containerregistry/pkg/v1/empty"
30+
"github.com/google/go-containerregistry/pkg/v1/layout"
3031
"github.com/google/go-containerregistry/pkg/v1/mutate"
3132
"github.com/google/go-containerregistry/pkg/v1/remote"
3233
"github.com/google/go-containerregistry/pkg/v1/tarball"
@@ -79,6 +80,7 @@ type buildParams struct {
7980
staticFiles map[string]string
8081
imageRefs []name.Tag
8182
publish bool
83+
outPath string
8284
ldflags string
8385
gotags string
8486
target string
@@ -96,6 +98,7 @@ func main() {
9698
ldflagsArg = flag.String("ldflags", "", "the --ldflags value to pass to go")
9799
gotags = flag.String("gotags", "", "the --tags value to pass to go")
98100
push = flag.Bool("push", false, "publish the image")
101+
outPath = flag.String("out-path", "", "write single images to a tarball, or multi-platform images to a folder")
99102
target = flag.String("target", "", "build for a specific env (options: flyio, local)")
100103
verbose = flag.Bool("v", false, "verbose build output")
101104
annotations = flag.String("annotations", "", `OCI image annotations https://github.com/opencontainers/image-spec/blob/main/annotations.md.
@@ -140,6 +143,7 @@ func main() {
140143
staticFiles: staticFiles,
141144
imageRefs: refs,
142145
publish: *push,
146+
outPath: *outPath,
143147
ldflags: *ldflagsArg,
144148
gotags: *gotags,
145149
target: *target,
@@ -198,6 +202,17 @@ func verifyPlatform(p v1.Platform, target string) error {
198202
return nil
199203
}
200204

205+
func writeImageToFile(img v1.Image, imgRef name.Reference, path string) error {
206+
if !strings.HasSuffix(path, ".tar") {
207+
return fmt.Errorf("out-path must end with .tar for single image, was: %s", path)
208+
}
209+
if err := tarball.WriteToFile(path, imgRef, img); err != nil {
210+
return err
211+
}
212+
213+
return nil
214+
}
215+
201216
func fetchAndBuild(bp *buildParams) error {
202217
ctx := context.Background()
203218
logf := log.Printf
@@ -243,25 +258,30 @@ func fetchAndBuild(bp *buildParams) error {
243258
if err != nil {
244259
return err
245260
}
246-
if !bp.publish {
247-
logf("not pushing")
248-
return nil
249-
}
250261

251-
img = mutate.Annotations(img, bp.annotations).(v1.Image) // OCI annotations
262+
switch {
263+
case bp.publish:
264+
img = mutate.Annotations(img, bp.annotations).(v1.Image) // OCI annotations
252265

253-
for _, r := range bp.imageRefs {
254-
if bp.target == "local" {
255-
if err := loadLocalImage(logf, r, img); err != nil {
266+
for _, r := range bp.imageRefs {
267+
if bp.target == "local" {
268+
if err := loadLocalImage(logf, r, img); err != nil {
269+
return err
270+
}
271+
continue
272+
}
273+
logf("pushing to %v", r)
274+
if err := remote.Write(r, img, remoteOpts...); err != nil {
256275
return err
257276
}
258-
continue
259-
}
260-
logf("pushing to %v", r)
261-
if err := remote.Write(r, img, remoteOpts...); err != nil {
262-
return err
263277
}
278+
return nil
279+
280+
case bp.outPath != "":
281+
return writeImageToFile(img, bp.imageRefs[0], bp.outPath)
264282
}
283+
logf("not pushing or writing to file")
284+
265285
return nil
266286
case types.OCIImageIndex, types.DockerManifestList:
267287
// baseRef is a multi-platform index, rest of the method handles this.
@@ -336,23 +356,28 @@ func fetchAndBuild(bp *buildParams) error {
336356
return err
337357
}
338358
logf("image digest: %v", d)
339-
if !bp.publish {
340-
logf("not pushing")
341-
return nil
342-
}
343359

344-
for _, r := range bp.imageRefs {
345-
if bp.target == "local" {
346-
if err := loadLocalImage(logf, r, img); err != nil {
360+
switch {
361+
case bp.publish:
362+
for _, r := range bp.imageRefs {
363+
if bp.target == "local" {
364+
if err := loadLocalImage(logf, r, img); err != nil {
365+
return err
366+
}
367+
continue
368+
}
369+
logf("pushing to %v", r)
370+
if err := remote.Write(r, img, remoteOpts...); err != nil {
347371
return err
348372
}
349-
continue
350-
}
351-
logf("pushing to %v", r)
352-
if err := remote.Write(r, img, remoteOpts...); err != nil {
353-
return err
354373
}
374+
return nil
375+
376+
case bp.outPath != "":
377+
return writeImageToFile(img, bp.imageRefs[0], bp.outPath)
355378
}
379+
logf("not pushing or writing to file")
380+
356381
return nil
357382
}
358383
if bp.target == "local" {
@@ -371,17 +396,35 @@ func fetchAndBuild(bp *buildParams) error {
371396
idx = mutate.Annotations(idx, bp.annotations).(v1.ImageIndex)
372397

373398
logf("index digest: %v", d)
374-
if !bp.publish {
375-
logf("not pushing")
399+
400+
switch {
401+
case bp.publish:
402+
for _, r := range bp.imageRefs {
403+
logf("pushing to %v", r)
404+
if err := remote.WriteIndex(r, idx, remoteOpts...); err != nil {
405+
return err
406+
}
407+
}
408+
376409
return nil
377-
}
378410

379-
for _, r := range bp.imageRefs {
380-
logf("pushing to %v", r)
381-
if err := remote.WriteIndex(r, idx, remoteOpts...); err != nil {
411+
case bp.outPath != "":
412+
fi, err := os.Stat(bp.outPath)
413+
if err != nil {
414+
if !os.IsNotExist(err) {
415+
return fmt.Errorf("checking out path: %w", err)
416+
}
417+
}
418+
if fi != nil && !fi.IsDir() {
419+
return fmt.Errorf("out-path must be a directory for multi-platform images: %s", bp.outPath)
420+
}
421+
if _, err := layout.Write(bp.outPath, idx); err != nil {
382422
return err
383423
}
424+
425+
return nil
384426
}
427+
logf("not pushing or writing to file")
385428

386429
return nil
387430
}

0 commit comments

Comments
 (0)