Browse Source

Add rm option to docker build to remove intermediate containers

Michael Crosby 11 years ago
parent
commit
b7a3fc687e

+ 6 - 1
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)

+ 8 - 7
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,
 	}
 }

+ 3 - 3
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 {

+ 4 - 0
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

+ 1 - 0
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
 

+ 1 - 0
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