diff --git a/components/engine/api.go b/components/engine/api.go index 25dea19e89..b6ab7badfa 100644 --- a/components/engine/api.go +++ b/components/engine/api.go @@ -774,6 +774,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ } remoteURL := r.FormValue("remote") repoName := r.FormValue("t") + rawSuppressOutput := r.FormValue("q") tag := "" if strings.Contains(repoName, ":") { remoteParts := strings.Split(repoName, ":") @@ -820,7 +821,13 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ } context = c } - b := NewBuildFile(srv, utils.NewWriteFlusher(w)) + + suppressOutput, err := getBoolParam(rawSuppressOutput) + if err != nil { + return err + } + + b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput) id, err := b.Build(context) if err != nil { fmt.Fprintf(w, "Error build: %s\n", err) diff --git a/components/engine/buildfile.go b/components/engine/buildfile.go index 38e6c330d6..7ade058c69 100644 --- a/components/engine/buildfile.go +++ b/components/engine/buildfile.go @@ -28,8 +28,8 @@ type buildFile struct { maintainer string config *Config context string + verbose bool - lastContainer *Container tmpContainers map[string]struct{} tmpImages map[string]struct{} @@ -254,7 +254,6 @@ func (b *buildFile) CmdAdd(args string) error { return err } b.tmpContainers[container.ID] = struct{}{} - b.lastContainer = container if err := container.EnsureMounted(); err != nil { return err @@ -290,7 +289,6 @@ func (b *buildFile) run() (string, error) { return "", err } b.tmpContainers[c.ID] = struct{}{} - b.lastContainer = c fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID)) // override the entry point that may have been picked up from the base image @@ -303,6 +301,13 @@ func (b *buildFile) run() (string, error) { return "", err } + if b.verbose { + err = <-c.Attach(nil, nil, b.out, b.out) + if err != nil { + return "", err + } + } + // Wait for it to finish if ret := c.Wait(); ret != 0 { return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret) @@ -337,7 +342,6 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error { return err } b.tmpContainers[container.ID] = struct{}{} - b.lastContainer = container fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID)) id = container.ID if err := container.EnsureMounted(); err != nil { @@ -365,29 +369,6 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error { } func (b *buildFile) Build(context io.Reader) (string, error) { - defer func() { - // If we have an error and a container, the display the logs - if b.lastContainer != nil { - fmt.Fprintf(b.out, "******** Logs from last container (%s) *******\n", b.lastContainer.ShortID()) - - cLog, err := b.lastContainer.ReadLog("stdout") - if err != nil { - utils.Debugf("Error reading logs (stdout): %s", err) - } - if _, err := io.Copy(b.out, cLog); err != nil { - utils.Debugf("Error streaming logs (stdout): %s", err) - } - cLog, err = b.lastContainer.ReadLog("stderr") - if err != nil { - utils.Debugf("Error reading logs (stderr): %s", err) - } - if _, err := io.Copy(b.out, cLog); err != nil { - utils.Debugf("Error streaming logs (stderr): %s", err) - } - fmt.Fprintf(b.out, "************* End of logs for %s *************\n", b.lastContainer.ShortID()) - } - }() - // FIXME: @creack any reason for using /tmp instead of ""? // FIXME: @creack "name" is a terrible variable name name, err := ioutil.TempDir("/tmp", "docker-build") @@ -440,7 +421,6 @@ func (b *buildFile) Build(context io.Reader) (string, error) { return "", ret.(error) } - b.lastContainer = nil fmt.Fprintf(b.out, " ---> %v\n", utils.TruncateID(b.image)) } if b.image != "" { @@ -450,7 +430,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) { return "", fmt.Errorf("An error occured during the build\n") } -func NewBuildFile(srv *Server, out io.Writer) BuildFile { +func NewBuildFile(srv *Server, out io.Writer, verbose bool) BuildFile { return &buildFile{ builder: NewBuilder(srv.runtime), runtime: srv.runtime, @@ -459,5 +439,6 @@ func NewBuildFile(srv *Server, out io.Writer) BuildFile { out: out, tmpContainers: make(map[string]struct{}), tmpImages: make(map[string]struct{}), + verbose: verbose, } } diff --git a/components/engine/buildfile_test.go b/components/engine/buildfile_test.go index b85a62cd05..2a1bebe156 100644 --- a/components/engine/buildfile_test.go +++ b/components/engine/buildfile_test.go @@ -114,7 +114,7 @@ func TestBuild(t *testing.T) { pushingPool: make(map[string]struct{}), } - buildfile := NewBuildFile(srv, ioutil.Discard) + buildfile := NewBuildFile(srv, ioutil.Discard, false) if _, err := buildfile.Build(mkTestContext(ctx.dockerfile, ctx.files, t)); err != nil { t.Fatal(err) } @@ -134,7 +134,7 @@ func TestVolume(t *testing.T) { pushingPool: make(map[string]struct{}), } - buildfile := NewBuildFile(srv, ioutil.Discard) + buildfile := NewBuildFile(srv, ioutil.Discard, false) imgId, err := buildfile.Build(mkTestContext(` from %s VOLUME /test @@ -150,7 +150,7 @@ CMD Hello world if len(img.Config.Volumes) == 0 { t.Fail() } - for key, _ := range img.Config.Volumes { + for key := range img.Config.Volumes { if key != "/test" { t.Fail() } diff --git a/components/engine/commands.go b/components/engine/commands.go index 3a91389e3b..f488ebc684 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -158,6 +158,8 @@ func mkBuildContext(dockerfile string, files [][2]string) (Archive, error) { func (cli *DockerCli) CmdBuild(args ...string) error { cmd := Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH") tag := cmd.String("t", "", "Tag to be applied to the resulting image in case of success") + suppressOutput := cmd.Bool("q", false, "Suppress verbose build output") + if err := cmd.Parse(args); err != nil { return nil } @@ -195,6 +197,10 @@ func (cli *DockerCli) CmdBuild(args ...string) error { // Upload the build context v := &url.Values{} v.Set("t", *tag) + + if *suppressOutput { + v.Set("q", "1") + } if isRemote { v.Set("remote", cmd.Arg(0)) } diff --git a/components/engine/docs/sources/api/docker_remote_api_v1.3.rst b/components/engine/docs/sources/api/docker_remote_api_v1.3.rst index 6542c8393b..9f33365e81 100644 --- a/components/engine/docs/sources/api/docker_remote_api_v1.3.rst +++ b/components/engine/docs/sources/api/docker_remote_api_v1.3.rst @@ -921,6 +921,7 @@ Build an image from Dockerfile via stdin The Content-type header should be set to "application/tar". :query t: tag to be applied to the resulting image in case of success + :query q: suppress verbose build output :statuscode 200: no error :statuscode 500: server error diff --git a/components/engine/docs/sources/commandline/command/build.rst b/components/engine/docs/sources/commandline/command/build.rst index 1645002ba2..45b6d2ec8e 100644 --- a/components/engine/docs/sources/commandline/command/build.rst +++ b/components/engine/docs/sources/commandline/command/build.rst @@ -11,6 +11,7 @@ Usage: docker build [OPTIONS] PATH | URL | - Build a new container image from the source code at PATH -t="": Tag to be applied to the resulting image in case of success. + -q=false: Suppress verbose build output. When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context