diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index aa93129c91..3f2a9f67ee 100644 --- a/builder/dockerfile/builder.go +++ b/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/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go index 09612e6e8d..9dad7e0f00 100644 --- a/builder/dockerfile/dispatchers.go +++ b/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/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 500727a481..7a57ade031 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/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"