소스 검색

Merge pull request #1384 from crosbymichael/1326-build-without-cache

* Builder: Add no cache for docker build
Guillaume J. Charmes 12 년 전
부모
커밋
ead7eb619e
6개의 변경된 파일126개의 추가작업 그리고 44개의 파일을 삭제
  1. 6 1
      api.go
  2. 31 24
      buildfile.go
  3. 83 19
      buildfile_test.go
  4. 4 0
      commands.go
  5. 1 0
      docs/sources/api/docker_remote_api_v1.4.rst
  6. 1 0
      docs/sources/commandline/command/build.rst

+ 6 - 1
api.go

@@ -793,6 +793,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")
+	rawNoCache := r.FormValue("nocache")
 	repoName, tag := utils.ParseRepositoryTag(repoName)
 
 	var context io.Reader
@@ -839,8 +840,12 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
 	if err != nil {
 		return err
 	}
+	noCache, err := getBoolParam(rawNoCache)
+	if err != nil {
+		return err
+	}
 
-	b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput)
+	b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache)
 	id, err := b.Build(context)
 	if err != nil {
 		fmt.Fprintf(w, "Error build: %s\n", err)

+ 31 - 24
buildfile.go

@@ -26,11 +26,12 @@ type buildFile struct {
 	builder *Builder
 	srv     *Server
 
-	image      string
-	maintainer string
-	config     *Config
-	context    string
-	verbose    bool
+	image        string
+	maintainer   string
+	config       *Config
+	context      string
+	verbose      bool
+	utilizeCache bool
 
 	tmpContainers map[string]struct{}
 	tmpImages     map[string]struct{}
@@ -94,15 +95,17 @@ func (b *buildFile) CmdRun(args string) error {
 
 	utils.Debugf("Command to be executed: %v", b.config.Cmd)
 
-	if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
-		return err
-	} else if cache != nil {
-		fmt.Fprintf(b.out, " ---> Using cache\n")
-		utils.Debugf("[BUILDER] Use cached version")
-		b.image = cache.ID
-		return nil
-	} else {
-		utils.Debugf("[BUILDER] Cache miss")
+	if b.utilizeCache {
+		if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
+			return err
+		} else if cache != nil {
+			fmt.Fprintf(b.out, " ---> Using cache\n")
+			utils.Debugf("[BUILDER] Use cached version")
+			b.image = cache.ID
+			return nil
+		} else {
+			utils.Debugf("[BUILDER] Cache miss")
+		}
 	}
 
 	cid, err := b.run()
@@ -397,16 +400,19 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
 		b.config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + comment}
 		defer func(cmd []string) { b.config.Cmd = cmd }(cmd)
 
-		if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
-			return err
-		} else if cache != nil {
-			fmt.Fprintf(b.out, " ---> Using cache\n")
-			utils.Debugf("[BUILDER] Use cached version")
-			b.image = cache.ID
-			return nil
-		} else {
-			utils.Debugf("[BUILDER] Cache miss")
+		if b.utilizeCache {
+			if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
+				return err
+			} else if cache != nil {
+				fmt.Fprintf(b.out, " ---> Using cache\n")
+				utils.Debugf("[BUILDER] Use cached version")
+				b.image = cache.ID
+				return nil
+			} else {
+				utils.Debugf("[BUILDER] Cache miss")
+			}
 		}
+
 		container, err := b.builder.Create(b.config)
 		if err != nil {
 			return err
@@ -500,7 +506,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, verbose bool) BuildFile {
+func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache bool) BuildFile {
 	return &buildFile{
 		builder:       NewBuilder(srv.runtime),
 		runtime:       srv.runtime,
@@ -510,5 +516,6 @@ func NewBuildFile(srv *Server, out io.Writer, verbose bool) BuildFile {
 		tmpContainers: make(map[string]struct{}),
 		tmpImages:     make(map[string]struct{}),
 		verbose:       verbose,
+		utilizeCache:  utilizeCache,
 	}
 }

+ 83 - 19
buildfile_test.go

@@ -195,21 +195,23 @@ func mkTestingFileServer(files [][2]string) (*httptest.Server, error) {
 
 func TestBuild(t *testing.T) {
 	for _, ctx := range testContexts {
-		buildImage(ctx, t)
+		buildImage(ctx, t, nil, true)
 	}
 }
 
-func buildImage(context testContextTemplate, t *testing.T) *Image {
-	runtime, err := newTestRuntime()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer nuke(runtime)
+func buildImage(context testContextTemplate, t *testing.T, srv *Server, useCache bool) *Image {
+	if srv == nil {
+		runtime, err := newTestRuntime()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer nuke(runtime)
 
-	srv := &Server{
-		runtime:     runtime,
-		pullingPool: make(map[string]struct{}),
-		pushingPool: make(map[string]struct{}),
+		srv = &Server{
+			runtime:     runtime,
+			pullingPool: make(map[string]struct{}),
+			pushingPool: make(map[string]struct{}),
+		}
 	}
 
 	httpServer, err := mkTestingFileServer(context.remoteFiles)
@@ -224,10 +226,10 @@ func buildImage(context testContextTemplate, t *testing.T) *Image {
 	}
 	port := httpServer.URL[idx+1:]
 
-	ip := runtime.networkManager.bridgeNetwork.IP
+	ip := srv.runtime.networkManager.bridgeNetwork.IP
 	dockerfile := constructDockerfile(context.dockerfile, ip, port)
 
-	buildfile := NewBuildFile(srv, ioutil.Discard, false)
+	buildfile := NewBuildFile(srv, ioutil.Discard, false, useCache)
 	id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
 	if err != nil {
 		t.Fatal(err)
@@ -245,7 +247,7 @@ func TestVolume(t *testing.T) {
         from {IMAGE}
         volume /test
         cmd Hello world
-    `, nil, nil}, t)
+    `, nil, nil}, t, nil, true)
 
 	if len(img.Config.Volumes) == 0 {
 		t.Fail()
@@ -261,7 +263,7 @@ func TestBuildMaintainer(t *testing.T) {
 	img := buildImage(testContextTemplate{`
         from {IMAGE}
         maintainer dockerio
-    `, nil, nil}, t)
+    `, nil, nil}, t, nil, true)
 
 	if img.Author != "dockerio" {
 		t.Fail()
@@ -273,7 +275,7 @@ func TestBuildEnv(t *testing.T) {
         from {IMAGE}
         env port 4243
         `,
-		nil, nil}, t)
+		nil, nil}, t, nil, true)
 	hasEnv := false
 	for _, envVar := range img.Config.Env {
 		if envVar == "port=4243" {
@@ -291,7 +293,7 @@ func TestBuildCmd(t *testing.T) {
         from {IMAGE}
         cmd ["/bin/echo", "Hello World"]
         `,
-		nil, nil}, t)
+		nil, nil}, t, nil, true)
 
 	if img.Config.Cmd[0] != "/bin/echo" {
 		t.Log(img.Config.Cmd[0])
@@ -308,7 +310,7 @@ func TestBuildExpose(t *testing.T) {
         from {IMAGE}
         expose 4243
         `,
-		nil, nil}, t)
+		nil, nil}, t, nil, true)
 
 	if img.Config.PortSpecs[0] != "4243" {
 		t.Fail()
@@ -320,8 +322,70 @@ func TestBuildEntrypoint(t *testing.T) {
         from {IMAGE}
         entrypoint ["/bin/echo"]
         `,
-		nil, nil}, t)
+		nil, nil}, t, nil, true)
 
 	if img.Config.Entrypoint[0] != "/bin/echo" {
 	}
 }
+
+func TestBuildImageWithCache(t *testing.T) {
+	runtime, err := newTestRuntime()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nuke(runtime)
+
+	srv := &Server{
+		runtime:     runtime,
+		pullingPool: make(map[string]struct{}),
+		pushingPool: make(map[string]struct{}),
+	}
+
+	template := testContextTemplate{`
+        from {IMAGE}
+        maintainer dockerio
+        `,
+		nil, nil}
+
+	img := buildImage(template, t, srv, true)
+	imageId := img.ID
+
+	img = nil
+	img = buildImage(template, t, srv, true)
+
+	if imageId != img.ID {
+		t.Logf("Image ids should match: %s != %s", imageId, img.ID)
+		t.Fail()
+	}
+}
+
+func TestBuildImageWithoutCache(t *testing.T) {
+	runtime, err := newTestRuntime()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nuke(runtime)
+
+	srv := &Server{
+		runtime:     runtime,
+		pullingPool: make(map[string]struct{}),
+		pushingPool: make(map[string]struct{}),
+	}
+
+	template := testContextTemplate{`
+        from {IMAGE}
+        maintainer dockerio
+        `,
+		nil, nil}
+
+	img := buildImage(template, t, srv, true)
+	imageId := img.ID
+
+	img = nil
+	img = buildImage(template, t, srv, false)
+
+	if imageId == img.ID {
+		t.Logf("Image ids should not match: %s == %s", imageId, img.ID)
+		t.Fail()
+	}
+}

+ 4 - 0
commands.go

@@ -160,6 +160,7 @@ 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")
+	noCache := cmd.Bool("no-cache", false, "Do not use cache when building the image")
 
 	if err := cmd.Parse(args); err != nil {
 		return nil
@@ -208,6 +209,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 	if isRemote {
 		v.Set("remote", cmd.Arg(0))
 	}
+	if *noCache {
+		v.Set("nocache", "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.4.rst

@@ -928,6 +928,7 @@ Build an image from Dockerfile via stdin
 
 	:query t: 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
 	:statuscode 200: no error
         :statuscode 500: server error
 

+ 1 - 0
docs/sources/commandline/command/build.rst

@@ -12,6 +12,7 @@
     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.
+      -no-cache: Do not use the cache when building the image.
     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