mirror of https://github.com/docker/cli.git
Compress after rewriting the archive.
Write a test showing compress failure. Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
74af31be7f
commit
a04aa8fe28
|
@ -77,16 +77,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 | -",
|
||||
|
@ -237,13 +241,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 {
|
||||
|
@ -292,6 +290,13 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package image
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"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
|
||||
}
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild}, ioutil.Discard)
|
||||
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)
|
||||
}
|
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ type FakeCli struct {
|
|||
out *command.OutStream
|
||||
err io.Writer
|
||||
in *command.InStream
|
||||
server command.ServerInfo
|
||||
}
|
||||
|
||||
// NewFakeCli returns a Cli backed by the fakeCli
|
||||
|
@ -27,6 +28,7 @@ func NewFakeCli(client client.APIClient, out io.Writer) *FakeCli {
|
|||
out: command.NewOutStream(out),
|
||||
err: ioutil.Discard,
|
||||
in: command.NewInStream(ioutil.NopCloser(strings.NewReader(""))),
|
||||
configfile: configfile.New("configfile"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,3 +71,8 @@ func (c *FakeCli) In() *command.InStream {
|
|||
func (c *FakeCli) ConfigFile() *configfile.ConfigFile {
|
||||
return c.configfile
|
||||
}
|
||||
|
||||
// ServerInfo returns API server information for the server used by this client
|
||||
func (c *FakeCli) ServerInfo() command.ServerInfo {
|
||||
return c.server
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue