From 00541f8de252419a61eba2c298454876e664fee9 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Thu, 16 Mar 2017 16:17:49 -0700 Subject: [PATCH] Fix cache for dockerfiles with multiple FROM Signed-off-by: Tonis Tiigi Upstream-commit: acad599210b5c00a4f3a8eae05de21d0d9ef8a88 Component: engine --- .../engine/builder/dockerfile/builder.go | 11 ++++++--- .../engine/builder/dockerfile/dispatchers.go | 2 +- .../integration-cli/docker_cli_build_test.go | 24 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/components/engine/builder/dockerfile/builder.go b/components/engine/builder/dockerfile/builder.go index aa93129c91..3f2a9f67ee 100644 --- a/components/engine/builder/dockerfile/builder.go +++ b/components/engine/builder/dockerfile/builder.go @@ -147,9 +147,6 @@ func NewBuilder(clientCtx context.Context, config *types.ImageBuildOptions, back LookingForDirectives: true, }, } - if icb, ok := backend.(builder.ImageCacheBuilder); ok { - b.imageCache = icb.MakeImageCache(config.CacheFrom) - } parser.SetEscapeToken(parser.DefaultEscapeToken, &b.directive) // Assume the default token for escape @@ -163,6 +160,14 @@ func NewBuilder(clientCtx context.Context, config *types.ImageBuildOptions, back return b, nil } +func (b *Builder) resetImageCache() { + if icb, ok := b.docker.(builder.ImageCacheBuilder); ok { + b.imageCache = icb.MakeImageCache(b.options.CacheFrom) + } + b.noBaseImage = false + b.cacheBusted = false +} + // sanitizeRepoAndTags parses the raw "t" parameter received from the client // to a slice of repoAndTag. // It also validates each repoName and tag. diff --git a/components/engine/builder/dockerfile/dispatchers.go b/components/engine/builder/dockerfile/dispatchers.go index 09612e6e8d..9dad7e0f00 100644 --- a/components/engine/builder/dockerfile/dispatchers.go +++ b/components/engine/builder/dockerfile/dispatchers.go @@ -205,7 +205,7 @@ func from(b *Builder, args []string, attributes map[string]bool, original string var image builder.Image - b.noBaseImage = false + b.resetImageCache() // Windows cannot support a container with no base image. if name == api.NoBaseImageSpecifier { diff --git a/components/engine/integration-cli/docker_cli_build_test.go b/components/engine/integration-cli/docker_cli_build_test.go index 500727a481..7a57ade031 100644 --- a/components/engine/integration-cli/docker_cli_build_test.go +++ b/components/engine/integration-cli/docker_cli_build_test.go @@ -5594,6 +5594,30 @@ func (s *DockerSuite) TestBuildCacheFrom(c *check.C) { c.Assert(layers1[len(layers1)-1], checker.Not(checker.Equals), layers2[len(layers1)-1]) } +func (s *DockerSuite) TestBuildCacheMultipleFrom(c *check.C) { + testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows + dockerfile := ` + FROM busybox + ADD baz / + FROM busybox + ADD baz /` + ctx := fakeContext(c, dockerfile, map[string]string{ + "Dockerfile": dockerfile, + "baz": "baz", + }) + defer ctx.Close() + + result := buildImage("build1", withExternalBuildContext(ctx)) + result.Assert(c, icmd.Success) + // second part of dockerfile was a repeat of first so should be cached + c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 1) + + result = buildImage("build2", withBuildFlags("--cache-from=build1"), withExternalBuildContext(ctx)) + result.Assert(c, icmd.Success) + // now both parts of dockerfile should be cached + c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 2) +} + func (s *DockerSuite) TestBuildNetNone(c *check.C) { testRequires(c, DaemonIsLinux) name := "testbuildnetnone"