Skip to content

Instantly share code, notes, and snippets.

@gdanko
Created November 21, 2018 03:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gdanko/94aaf2770f586d0490c3c4a941544c13 to your computer and use it in GitHub Desktop.
Save gdanko/94aaf2770f586d0490c3c4a941544c13 to your computer and use it in GitHub Desktop.
package main
import (
"archive/tar"
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
type StreamMessage struct {
Stream string `json:"stream,omitempty"`
}
type AuxMessage struct {
Aux struct {
ID string `json:"ID"`
} `json:"aux"`
}
func main() {
cli, err := generateDockerCLI()
if err != nil {
panic(err)
}
dockerPath := "/Users/gdanko/go/planB"
dockerFile := "Dockerfile"
dockerBuildContext, err := getBuildContext(dockerPath)
if err != nil {
panic(err)
}
options := types.ImageBuildOptions{
// https://godoc.org/docker.io/go-docker/api/types#ImageBuildOptions
SuppressOutput: false,
NoCache: true,
CgroupParent: "cgroup_parent",
Tags: []string{"dummy:latest"},
Context: dockerBuildContext,
Dockerfile: dockerFile,
Remove: true,
}
imageBuildResponse, err := cli.ImageBuild(
context.Background(),
dockerBuildContext,
options,
)
if err != nil {
fmt.Println("*** error ***")
panic(err)
} else {
fmt.Println("*** success ***")
fmt.Println(imageBuildResponse)
}
defer imageBuildResponse.Body.Close()
fmt.Println("")
fmt.Println("*** ImageBuild output ***")
buf := new(bytes.Buffer)
buf.ReadFrom(imageBuildResponse.Body)
var streamMessage StreamMessage
var auxMessage AuxMessage
for _, line := range strings.Split(buf.String(), "\n") {
if err = json.Unmarshal([]byte(line), &streamMessage); err == nil {
if streamMessage.Stream != "\n" {
fmt.Println(strings.TrimSpace(streamMessage.Stream))
}
// the AuxMessage struct is being caught above. Why?
} else if err = json.Unmarshal([]byte(line), &auxMessage); err == nil {
fmt.Printf(auxMessage.Aux.ID)
}
}
}
func generateDockerCLI() (cli *client.Client, err error) {
cli, err = client.NewClientWithOpts(client.WithVersion("1.37"))
return cli, err
}
func getBuildContext(uuidPath string) (dockerFileTarReader io.Reader, err error) {
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
defer tw.Close()
err = filepath.Walk(uuidPath, func(path string, info os.FileInfo, err error) error {
f, err := os.Stat(path)
if err != nil {
return err
}
// Excluding .git folder
// TBD: parse .dockerignore and exclude the files listed from context
if f.IsDir() == false && !strings.HasPrefix(path, uuidPath+"/.git") {
pathReader, err := os.Open(path)
if err != nil {
panic(err)
}
defer pathReader.Close()
readPath, err := ioutil.ReadAll(pathReader)
if err != nil {
panic(err)
}
file, err := os.OpenFile(path, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer file.Close()
info, err := file.Stat()
if err != nil {
return err
}
rel, err := filepath.Rel(uuidPath, path)
if err != nil {
return err
}
fmt.Printf("\x1b[21m\x1b[34mTarring => %s\x1b[0m\n", rel)
tarHeader := &tar.Header{
Name: rel,
Size: info.Size(),
Mode: int64(info.Mode()),
ModTime: info.ModTime(),
}
if err := tw.WriteHeader(tarHeader); err != nil {
fmt.Printf("\x1b[1m\033[31mUnable to write tar header: %s\x1b[0m", err)
return err
}
if _, err = tw.Write(readPath); err != nil {
fmt.Printf("\x1b[1m\033[31mUnable to write tar body: %s\x1b[0m", err)
return err
}
}
return nil
})
if err != nil {
return bytes.NewReader(buf.Bytes()), err
}
dockerFileTarReader = bytes.NewReader(buf.Bytes())
return dockerFileTarReader, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment