91 lines
2.0 KiB
Go
91 lines
2.0 KiB
Go
package docker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/client"
|
|
)
|
|
|
|
func SaveImageTar(ctx context.Context, image, path, name string, doPull, rm bool) error {
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
|
if err != nil {
|
|
return fmt.Errorf("docker client error: %v", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
if doPull {
|
|
if err := pullImage(ctx, cli, image); err != nil {
|
|
return fmt.Errorf("pull image %s failed: %v", image, err)
|
|
}
|
|
}
|
|
|
|
if err := saveToTar(ctx, cli, image, path, name); err != nil {
|
|
return fmt.Errorf("save image %s failed: %v", image, err)
|
|
}
|
|
|
|
if rm {
|
|
if err := rmImage(ctx, cli, image); err != nil {
|
|
return fmt.Errorf("remove image %s failed: %v", image, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func pullImage(ctx context.Context, cli *client.Client, image string) error {
|
|
// try pull image
|
|
r, err := cli.ImagePull(ctx, image, types.ImagePullOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("pull image %s failed: %v", image, err)
|
|
}
|
|
defer r.Close()
|
|
|
|
io.Copy(os.Stdout, r)
|
|
|
|
return nil
|
|
}
|
|
|
|
func rmImage(ctx context.Context, cli *client.Client, image string) error {
|
|
_, err := cli.ImageRemove(ctx, image, types.ImageRemoveOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func saveToTar(ctx context.Context, cli *client.Client, image, path, name string) error {
|
|
out, err := cli.ImageSave(ctx, []string{image})
|
|
if err != nil {
|
|
return fmt.Errorf("save image %s failed: %v", image, err)
|
|
}
|
|
defer out.Close()
|
|
|
|
filename := name
|
|
if filename == "" {
|
|
strs := strings.Split(image, "/")
|
|
filename = fmt.Sprintf("%s.tar", strings.ReplaceAll(strs[len(strs)-1], ":", "_"))
|
|
}
|
|
|
|
filep := filepath.Join(path, filename)
|
|
|
|
target, err := os.Create(filep)
|
|
if err != nil {
|
|
return fmt.Errorf("create file %s failed: %v", filep, err)
|
|
}
|
|
defer target.Close()
|
|
|
|
if _, err := io.Copy(target, out); err != nil {
|
|
return fmt.Errorf("copy file %s failed: %v", filep, err)
|
|
}
|
|
|
|
return nil
|
|
}
|