Skip to content

Commit

Permalink
Compress after rewriting the archive.
Browse files Browse the repository at this point in the history
Write a test showing compress failure.

Signed-off-by: Daniel Nephin <[email protected]>
  • Loading branch information
dnephin committed Jun 23, 2017
1 parent 868cb74 commit fc176bf
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 10 deletions.
24 changes: 14 additions & 10 deletions cli/command/image/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,20 @@ func (o buildOptions) contextFromStdin() bool {
return o.context == "-"
}

// NewBuildCommand creates a new `docker build` command
func NewBuildCommand(dockerCli command.Cli) *cobra.Command {
func newBuildOptions() buildOptions {
ulimits := make(map[string]*units.Ulimit)
options := buildOptions{
return buildOptions{
tags: opts.NewListOpts(validateTag),
buildArgs: opts.NewListOpts(opts.ValidateEnv),
ulimits: opts.NewUlimitOpt(&ulimits),
labels: opts.NewListOpts(opts.ValidateEnv),
extraHosts: opts.NewListOpts(opts.ValidateExtraHost),
}
}

// NewBuildCommand creates a new `docker build` command
func NewBuildCommand(dockerCli command.Cli) *cobra.Command {
options := newBuildOptions()

cmd := &cobra.Command{
Use: "build [OPTIONS] PATH | URL | -",
Expand Down Expand Up @@ -228,13 +232,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
}

excludes = build.TrimBuildFilesFromExcludes(excludes, relDockerfile, options.dockerfileFromStdin())

compression := archive.Uncompressed
if options.compress {
compression = archive.Gzip
}
buildCtx, err = archive.TarWithOptions(contextDir, &archive.TarOptions{
Compression: compression,
ExcludePatterns: excludes,
})
if err != nil {
Expand Down Expand Up @@ -262,12 +260,18 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
buildCtx = replaceDockerfileTarWrapper(ctx, buildCtx, relDockerfile, translator, &resolvedTags)
}

if options.compress {
buildCtx, err = build.Compress(buildCtx)
if err != nil {
return err
}
}

// Setup an upload progress bar
progressOutput := streamformatter.NewProgressOutput(progBuff)
if !dockerCli.Out().IsTerminal() {
progressOutput = &lastProgressOutput{output: progressOutput}
}

var body io.Reader = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")

configFile := dockerCli.ConfigFile()
Expand Down
25 changes: 25 additions & 0 deletions cli/command/image/build/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/pools"
"github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/stringid"
Expand Down Expand Up @@ -375,3 +376,27 @@ func AddDockerfileToBuildContext(dockerfileCtx io.ReadCloser, buildCtx io.ReadCl
})
return buildCtx, randomName, nil
}

// Compress the build context for sending to the API
func Compress(buildCtx io.ReadCloser) (io.ReadCloser, error) {
pipeReader, pipeWriter := io.Pipe()

go func() {
compressWriter, err := archive.CompressStream(pipeWriter, archive.Gzip)
if err != nil {
pipeWriter.CloseWithError(err)
}
defer buildCtx.Close()

if _, err := pools.Copy(compressWriter, buildCtx); err != nil {
pipeWriter.CloseWithError(
errors.Wrap(err, "failed to compress context"))
compressWriter.Close()
return
}
compressWriter.Close()
pipeWriter.Close()
}()

return pipeReader, nil
}
73 changes: 73 additions & 0 deletions cli/command/image/build_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package image

import (
"bytes"
"io"
"io/ioutil"
"os"
"path/filepath"
"sort"
"testing"

"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)

func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
dest, err := ioutil.TempDir("", "test-build-compress-dest")
require.NoError(t, err)
defer os.RemoveAll(dest)

var dockerfileName string
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
buffer := new(bytes.Buffer)
tee := io.TeeReader(context, buffer)

assert.NoError(t, archive.Untar(tee, dest, nil))
dockerfileName = options.Dockerfile

header := buffer.Bytes()[:10]
assert.Equal(t, archive.Gzip, archive.DetectCompression(header))

body := new(bytes.Buffer)
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
}

out := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild}, out)
cli.SetConfigfile(configfile.NewConfigFile("filename"))
dockerfile := bytes.NewBufferString(`
FROM alpine:3.6
COPY foo /
`)
cli.SetIn(command.NewInStream(ioutil.NopCloser(dockerfile)))

dir, err := ioutil.TempDir("", "test-build-compress")
require.NoError(t, err)
defer os.RemoveAll(dir)

ioutil.WriteFile(filepath.Join(dir, "foo"), []byte("some content"), 0644)

options := newBuildOptions()
options.compress = true
options.dockerfileName = "-"
options.context = dir

err = runBuild(cli, options)
require.NoError(t, err)

files, err := ioutil.ReadDir(dest)
require.NoError(t, err)
actual := []string{}
for _, fileInfo := range files {
actual = append(actual, fileInfo.Name())
}
sort.Strings(actual)
assert.Equal(t, []string{dockerfileName, ".dockerignore", "foo"}, actual)
}
8 changes: 8 additions & 0 deletions cli/command/image/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type fakeClient struct {
imageInspectFunc func(image string) (types.ImageInspect, []byte, error)
imageImportFunc func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error)
imageHistoryFunc func(image string) ([]image.HistoryResponseItem, error)
imageBuildFunc func(context.Context, io.Reader, types.ImageBuildOptions) (types.ImageBuildResponse, error)
}

func (cli *fakeClient) ImageTag(_ context.Context, image, ref string) error {
Expand Down Expand Up @@ -114,3 +115,10 @@ func (cli *fakeClient) ImageHistory(_ context.Context, img string) ([]image.Hist
}
return []image.HistoryResponseItem{{ID: img, Created: time.Now().Unix()}}, nil
}

func (cli *fakeClient) ImageBuild(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
if cli.imageBuildFunc != nil {
return cli.imageBuildFunc(ctx, context, options)
}
return types.ImageBuildResponse{Body: ioutil.NopCloser(strings.NewReader(""))}, nil
}

0 comments on commit fc176bf

Please sign in to comment.