diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index e3d49f034e0..9d0f534991c 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -121,7 +121,8 @@ type executor struct { useCache bool removeIntermediateCtrs bool forceRmIntermediateCtrs bool - imageMap map[string]string // Used to map images that we create to handle the AS construct. + imageMap map[string]string // Used to map images that we create to handle the AS construct (stage name to image ID). + imageDigestMap map[string]string // Used to map images that we create to handle the AS construct (stage name to image (manifest) digest). containerMap map[string]*buildah.Builder // Used to map from image names to only-created-for-the-rootfs containers. baseMap map[string]struct{} // Holds the names of every base image, as given. rootfsMap map[string]struct{} // Holds the names of every stage whose rootfs is referenced in a COPY or ADD instruction. @@ -325,6 +326,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o removeIntermediateCtrs: options.RemoveIntermediateCtrs, forceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, imageMap: make(map[string]string), + imageDigestMap: make(map[string]string), containerMap: make(map[string]*buildah.Builder), baseMap: make(map[string]struct{}), rootfsMap: make(map[string]struct{}), @@ -1162,6 +1164,7 @@ func (b *executor) Build(ctx context.Context, stages imagebuilder.Stages) (image // that we can look it up later. if r.Index < len(stages)-1 && r.ImageID != "" { b.imageMap[stage.Name] = r.ImageID + b.imageDigestMap[stage.Name] = r.CommitResults.Digest.String() // We're not populating the cache with intermediate // images, so add this one to the list of images that // we'll remove later. diff --git a/imagebuildah/stage_executor.go b/imagebuildah/stage_executor.go index 8cf55bbbd84..2a072b8d9ee 100644 --- a/imagebuildah/stage_executor.go +++ b/imagebuildah/stage_executor.go @@ -2055,7 +2055,7 @@ func (s *stageExecutor) getCreatedBy(node *parser.Node, addedContentSummary stri if mountOptionFrom != "" { if stage, ok := s.executor.stages[mountOptionFrom]; ok { // If source is a previous stage then checksum is image digest for that stage - if image, isPreviousStage := s.executor.imageMap[stage.name]; isPreviousStage { + if image, isPreviousStage := s.executor.imageDigestMap[stage.name]; isPreviousStage { mountCheckSum = image } } else { diff --git a/tests/bud.bats b/tests/bud.bats index d7b9f71af84..1a1a4813592 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -753,6 +753,31 @@ _EOF expect_output --substring "anotherfile" } +@test "bud --layers with --mount type bind should burst cache if content is changed - source is previous stage" { + _prefetch busybox + local contextdir=${TEST_SCRATCH_DIR}/cache + mkdir -p $contextdir + + for iteration in 1 2 ; do + for content in 1 2 ; do + # based on reproducer from #6845 + cat > $contextdir/Containerfile <<-_EOF + FROM busybox AS base + + FROM base AS builder + RUN mkdir /build && echo "$content" > /build/foo.txt + + FROM base AS prod + RUN --mount=type=bind,source=/build,from=builder,target=/build cp /build/foo.txt bar.txt +_EOF + run_buildah build $WITH_POLICY_JSON --layers --iidfile ${TEST_SCRATCH_DIR}/$content.$iteration.txt $contextdir + done + done + assert $(< ${TEST_SCRATCH_DIR}/1.1.txt) == $(< ${TEST_SCRATCH_DIR}/1.2.txt) + assert $(< ${TEST_SCRATCH_DIR}/2.1.txt) == $(< ${TEST_SCRATCH_DIR}/2.2.txt) + assert $(< ${TEST_SCRATCH_DIR}/1.1.txt) != $(< ${TEST_SCRATCH_DIR}/2.1.txt) +} + @test "bud --layers should not hit cache if heredoc is changed" { _prefetch alpine local contextdir=${TEST_SCRATCH_DIR}/bud/platform