diff --git a/api.go b/api.go index 5d565ef4dc..3a2aadc33f 100644 --- a/api.go +++ b/api.go @@ -833,6 +833,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ repoName := r.FormValue("t") rawSuppressOutput := r.FormValue("q") rawNoCache := r.FormValue("nocache") + rawRm := r.FormValue("rm") repoName, tag := utils.ParseRepositoryTag(repoName) var context io.Reader @@ -883,8 +884,12 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ if err != nil { return err } + rm, err := getBoolParam(rawRm) + if err != nil { + return err + } - b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache) + b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache, rm) id, err := b.Build(context) if err != nil { fmt.Fprintf(w, "Error build: %s\n", err) diff --git a/buildfile.go b/buildfile.go index 28ba54e55f..7f2ea00643 100644 --- a/buildfile.go +++ b/buildfile.go @@ -30,6 +30,7 @@ type buildFile struct { context string verbose bool utilizeCache bool + rm bool tmpContainers map[string]struct{} tmpImages map[string]struct{} @@ -37,15 +38,11 @@ type buildFile struct { out io.Writer } -func (b *buildFile) clearTmp(containers, images map[string]struct{}) { +func (b *buildFile) clearTmp(containers map[string]struct{}) { for c := range containers { tmp := b.runtime.Get(c) b.runtime.Destroy(tmp) - utils.Debugf("Removing container %s", c) - } - for i := range images { - b.runtime.graph.Delete(i) - utils.Debugf("Removing image %s", i) + fmt.Fprintf(b.out, "Removing intermediate container %s\n", utils.TruncateID(c)) } } @@ -514,12 +511,15 @@ func (b *buildFile) Build(context io.Reader) (string, error) { } if b.image != "" { fmt.Fprintf(b.out, "Successfully built %s\n", utils.TruncateID(b.image)) + if b.rm { + b.clearTmp(b.tmpContainers) + } return b.image, nil } return "", fmt.Errorf("An error occurred during the build\n") } -func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache bool) BuildFile { +func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache, rm bool) BuildFile { return &buildFile{ runtime: srv.runtime, srv: srv, @@ -529,5 +529,6 @@ func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache bool) BuildF tmpImages: make(map[string]struct{}), verbose: verbose, utilizeCache: utilizeCache, + rm: rm, } } diff --git a/buildfile_test.go b/buildfile_test.go index 995b5b9f38..c3881a214f 100644 --- a/buildfile_test.go +++ b/buildfile_test.go @@ -257,7 +257,7 @@ func buildImage(context testContextTemplate, t *testing.T, srv *Server, useCache ip := srv.runtime.networkManager.bridgeNetwork.IP dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := NewBuildFile(srv, ioutil.Discard, false, useCache) + buildfile := NewBuildFile(srv, ioutil.Discard, false, useCache, false) id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t)) if err != nil { t.Fatal(err) @@ -498,7 +498,7 @@ func TestForbiddenContextPath(t *testing.T) { ip := srv.runtime.networkManager.bridgeNetwork.IP dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := NewBuildFile(srv, ioutil.Discard, false, true) + buildfile := NewBuildFile(srv, ioutil.Discard, false, true, false) _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t)) if err == nil { @@ -546,7 +546,7 @@ func TestBuildADDFileNotFound(t *testing.T) { ip := srv.runtime.networkManager.bridgeNetwork.IP dockerfile := constructDockerfile(context.dockerfile, ip, port) - buildfile := NewBuildFile(srv, ioutil.Discard, false, true) + buildfile := NewBuildFile(srv, ioutil.Discard, false, true, false) _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t)) if err == nil { diff --git a/commands.go b/commands.go index 00eeaf3881..62d42b9874 100644 --- a/commands.go +++ b/commands.go @@ -165,6 +165,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { tag := cmd.String("t", "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success") suppressOutput := cmd.Bool("q", false, "Suppress verbose build output") noCache := cmd.Bool("no-cache", false, "Do not use cache when building the image") + rm := cmd.Bool("rm", false, "Remove intermediate containers after a successful build") if err := cmd.Parse(args); err != nil { return nil } @@ -215,6 +216,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error { if *noCache { v.Set("nocache", "1") } + if *rm { + v.Set("rm", "1") + } req, err := http.NewRequest("POST", fmt.Sprintf("/v%g/build?%s", APIVERSION, v.Encode()), body) if err != nil { return err diff --git a/contrib/docker.bash b/contrib/docker.bash index 63df98825c..aa9fb3d7b5 100644 --- a/contrib/docker.bash +++ b/contrib/docker.bash @@ -114,7 +114,7 @@ _docker_build() case "$cur" in -*) - COMPREPLY=( $( compgen -W "-no-cache -t -q" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "-no-cache -t -q -rm" -- "$cur" ) ) ;; *) _filedir diff --git a/docs/sources/api/docker_remote_api_v1.5.rst b/docs/sources/api/docker_remote_api_v1.5.rst index 4f994f5bf0..88fe5e7307 100644 --- a/docs/sources/api/docker_remote_api_v1.5.rst +++ b/docs/sources/api/docker_remote_api_v1.5.rst @@ -976,6 +976,7 @@ Build an image from Dockerfile via stdin :query t: repository name (and optionally a tag) to be applied to the resulting image in case of success :query q: suppress verbose build output :query nocache: do not use the cache when building the image + :query rm: remove intermediate containers after a successful build :statuscode 200: no error :statuscode 500: server error diff --git a/docs/sources/commandline/command/build.rst b/docs/sources/commandline/command/build.rst index cc36aa0dd9..5ce70d85d9 100644 --- a/docs/sources/commandline/command/build.rst +++ b/docs/sources/commandline/command/build.rst @@ -13,6 +13,7 @@ -t="": Repository name (and optionally a tag) to be applied to the resulting image in case of success. -q=false: Suppress verbose build output. -no-cache: Do not use the cache when building the image. + -rm: Remove intermediate containers after a successful build 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