| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- package docker
- import (
- "archive/tar"
- "bytes"
- "context"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "time"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/pkg/archive"
- "github.com/moby/moby/pkg/jsonmessage"
- "github.com/moby/moby/pkg/stringid"
- "github.com/moby/term"
- "github.com/pkg/errors"
- )
- type BuildOpts struct {
- ImageRepo string
- Tag string
- CurrentTag string
- BuildContext string
- DockerfilePath string
- IsDockerfileInCtx bool
- Env map[string]string
- }
- // BuildLocal
- func (a *Agent) BuildLocal(opts *BuildOpts) error {
- dockerfilePath := opts.DockerfilePath
- tar, err := archive.TarWithOptions(opts.BuildContext, &archive.TarOptions{})
- if err != nil {
- return err
- }
- if !opts.IsDockerfileInCtx {
- dockerfileCtx, err := os.Open(dockerfilePath)
- if err != nil {
- return errors.Errorf("unable to open Dockerfile: %v", err)
- }
- defer dockerfileCtx.Close()
- // add the dockerfile to the build context
- tar, dockerfilePath, err = AddDockerfileToBuildContext(dockerfileCtx, tar)
- if err != nil {
- return err
- }
- }
- buildArgs := make(map[string]*string)
- for key, val := range opts.Env {
- valCopy := val
- buildArgs[key] = &valCopy
- }
- out, err := a.client.ImageBuild(context.Background(), tar, types.ImageBuildOptions{
- Dockerfile: dockerfilePath,
- BuildArgs: buildArgs,
- Tags: []string{
- fmt.Sprintf("%s:%s", opts.ImageRepo, opts.Tag),
- },
- CacheFrom: []string{
- fmt.Sprintf("%s:%s", opts.ImageRepo, opts.CurrentTag),
- },
- Remove: true,
- Platform: "linux/amd64",
- })
- if err != nil {
- return err
- }
- defer out.Body.Close()
- termFd, isTerm := term.GetFdInfo(os.Stderr)
- return jsonmessage.DisplayJSONMessagesStream(out.Body, os.Stderr, termFd, isTerm, nil)
- }
- // AddDockerfileToBuildContext from a ReadCloser, returns a new archive and
- // the relative path to the dockerfile in the context.
- func AddDockerfileToBuildContext(dockerfileCtx io.ReadCloser, buildCtx io.ReadCloser) (io.ReadCloser, string, error) {
- file, err := ioutil.ReadAll(dockerfileCtx)
- dockerfileCtx.Close()
- if err != nil {
- return nil, "", err
- }
- now := time.Now()
- hdrTmpl := &tar.Header{
- Mode: 0600,
- Uid: 0,
- Gid: 0,
- ModTime: now,
- Typeflag: tar.TypeReg,
- AccessTime: now,
- ChangeTime: now,
- }
- randomName := ".dockerfile." + stringid.GenerateRandomID()[:20]
- buildCtx = archive.ReplaceFileTarWrapper(buildCtx, map[string]archive.TarModifierFunc{
- // Add the dockerfile with a random filename
- randomName: func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
- return hdrTmpl, file, nil
- },
- // Update .dockerignore to include the random filename
- ".dockerignore": func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
- if h == nil {
- h = hdrTmpl
- }
- b := &bytes.Buffer{}
- if content != nil {
- if _, err := b.ReadFrom(content); err != nil {
- return nil, nil, err
- }
- } else {
- b.WriteString(".dockerignore")
- }
- b.WriteString("\n" + randomName + "\n")
- return h, b.Bytes(), nil
- },
- })
- return buildCtx, randomName, nil
- }
|