github.com/git-ogawa/go-dbyml@v1.2.1/dbyml/image.go (about)

     1  package dbyml
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"os"
     8  	"reflect"
     9  
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/client"
    12  	"github.com/docker/docker/pkg/jsonmessage"
    13  	"github.com/moby/term"
    14  )
    15  
    16  // ImageInfo defines docker image information.
    17  type ImageInfo struct {
    18  	Basename   string             `yaml:"name"`        // Image name
    19  	Tag        string             `yaml:"tag"`         // Image tag
    20  	ImageName  string             `yaml:"image_name"`  // Image name such as `go-dbyml:latest`
    21  	Context    string             `yaml:"path"`        // Path to the directory where Dockerfile exists, is equivalent to build context
    22  	Dockerfile string             `yaml:"dockerfile"`  // Dockerfile filename
    23  	BuildArgs  map[string]*string `yaml:"build_args"`  // Build-args to be passed to image on build
    24  	Labels     map[string]string  `yaml:"label"`       // Labels to be passed to image on build
    25  	DockerHost string             `yaml:"docker_host"` // Docker host such as "unix:///var/run/docker.sock"
    26  
    27  	DockerfilePath string
    28  	Registry       RegistryInfo
    29  	BuildInfo      BuildInfo
    30  	FullName       string
    31  	DockerClient   *client.Client
    32  }
    33  
    34  // NewImageInfo creates a new ImageInfo struct with default values.
    35  func NewImageInfo() *ImageInfo {
    36  	image := new(ImageInfo)
    37  	image.Tag = "latest"
    38  	image.Context = "."
    39  	image.Dockerfile = "Dockerfile"
    40  	image.DockerHost = "unix:///var/run/docker.sock"
    41  	image.DockerfilePath = image.Context + "/" + image.Dockerfile
    42  	image.Registry = *NewRegistryInfo()
    43  	image.BuildInfo = *NewBuildInfo()
    44  	return image
    45  }
    46  
    47  // SetProperties sets some properties when build an image.
    48  func (image *ImageInfo) SetProperties() {
    49  	image.ImageName = image.Basename + ":" + image.Tag
    50  	image.DockerfilePath = image.Context + "/" + image.Dockerfile
    51  	image.SetDockerClient()
    52  }
    53  
    54  // SetDockerClient initializes docker api client for the specified host.
    55  func (image *ImageInfo) SetDockerClient() {
    56  	image.DockerClient, _ = client.NewClientWithOpts(
    57  		client.WithHost(image.DockerHost),
    58  		client.WithAPIVersionNegotiation(),
    59  	)
    60  }
    61  
    62  // ShowProperties shows the current settings related to image build.
    63  func (image ImageInfo) ShowProperties() {
    64  	rv := reflect.ValueOf(image)
    65  	rt := rv.Type()
    66  	for i := 0; i < rt.NumField(); i++ {
    67  		field := rt.Field(i)
    68  		kind := field.Type.Kind()
    69  		value := rv.FieldByName(field.Name)
    70  		if kind == reflect.Map || kind == reflect.Slice {
    71  			showMapElement(field.Name, value.MapRange())
    72  		} else if kind == reflect.String && value.Interface() != "" {
    73  			fmt.Printf("%-30v: %v\n", field.Name, value)
    74  		}
    75  	}
    76  }
    77  
    78  // Build runs image build.
    79  func (image *ImageInfo) Build() error {
    80  	buf := GetBuildContext(image.Context)
    81  	tar := bytes.NewReader(buf.Bytes())
    82  	ctx := context.Background()
    83  
    84  	options := types.ImageBuildOptions{
    85  		NoCache:    image.BuildInfo.NoCache,
    86  		Dockerfile: image.DockerfilePath,
    87  		Remove:     true,
    88  		BuildArgs:  image.BuildArgs,
    89  		Labels:     image.Labels,
    90  		Target:     image.BuildInfo.Target,
    91  		Tags:       []string{image.ImageName},
    92  	}
    93  
    94  	res, err := image.DockerClient.ImageBuild(ctx, tar, options)
    95  	if err != nil {
    96  		return err
    97  	}
    98  	defer res.Body.Close()
    99  
   100  	termFd, isTerm := term.GetFdInfo(os.Stderr)
   101  	err = jsonmessage.DisplayJSONMessagesStream(res.Body, os.Stderr, termFd, isTerm, nil)
   102  	return err
   103  }
   104  
   105  // SetFullImageName sets image name for pushing to a registry.
   106  func (image *ImageInfo) SetFullImageName() {
   107  	if image.Registry.Project != "" {
   108  		image.FullName = image.Registry.Host + "/" + image.Registry.Project + "/" + image.ImageName
   109  	} else {
   110  		image.FullName = image.Registry.Host + "/" + image.ImageName
   111  	}
   112  }
   113  
   114  // Push runs image push to a registry.
   115  func (image *ImageInfo) Push() error {
   116  	ctx := context.Background()
   117  	image.AddTag()
   118  
   119  	opts := types.ImagePushOptions{All: false, RegistryAuth: image.Registry.BasicAuth()}
   120  
   121  	res, err := image.DockerClient.ImagePush(ctx, image.FullName, opts)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	defer res.Close()
   126  
   127  	termFd, isTerm := term.GetFdInfo(os.Stderr)
   128  	err = jsonmessage.DisplayJSONMessagesStream(res, os.Stderr, termFd, isTerm, nil)
   129  	return err
   130  }
   131  
   132  // AddTag adds a tag containing the registry name to a built image.
   133  func (image *ImageInfo) AddTag() {
   134  	ctx := context.Background()
   135  	image.SetFullImageName()
   136  
   137  	err := image.DockerClient.ImageTag(ctx, image.ImageName, image.FullName)
   138  	if err != nil {
   139  		panic(err)
   140  	}
   141  }