Fix copier when using globs

In Docker if you are copying more then one object, and
one of them is successful, then the command is successful. Currently in
buildah each glob has to be successful. This PR matches Buildah to
Docker.

Fixes: https://github.com/containers/podman/issues/9594

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2021-04-19 06:22:41 -04:00
parent b747f5d5e3
commit 37e9d254cc
No known key found for this signature in database
GPG Key ID: A2DF901DABE2C028
11 changed files with 64 additions and 6 deletions

8
add.go
View File

@ -224,7 +224,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
}
localSourceStats, err = copier.Stat(contextDir, contextDir, statOptions, localSources)
if err != nil {
return errors.Wrapf(err, "error checking on sources %v under %q", localSources, contextDir)
return errors.Wrapf(err, "checking on sources under %q", contextDir)
}
}
numLocalSourceItems := 0
@ -238,10 +238,10 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
errorText = fmt.Sprintf("possible escaping context directory error: %s", errorText)
}
return errors.Errorf("error checking on source %v under %q: %v", localSourceStat.Glob, contextDir, errorText)
return errors.Errorf("checking on sources under %q: %v", contextDir, errorText)
}
if len(localSourceStat.Globbed) == 0 {
return errors.Wrapf(syscall.ENOENT, "error checking on source %v under %q: no glob matches", localSourceStat.Glob, contextDir)
return errors.Wrapf(syscall.ENOENT, "checking source under %q: no glob matches", contextDir)
}
numLocalSourceItems += len(localSourceStat.Globbed)
}
@ -433,7 +433,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
}
}
if localSourceStat == nil {
return errors.Errorf("internal error: should have statted %s, but we didn't?", src)
continue
}
// Iterate through every item that matched the glob.

View File

@ -988,11 +988,13 @@ func copierHandlerStat(req request, pm *fileutils.PatternMatcher) *response {
s := StatsForGlob{
Glob: req.preservedGlobs[i],
}
stats = append(stats, &s)
// glob this pattern
globMatched, err := filepath.Glob(glob)
if err != nil {
s.Error = fmt.Sprintf("copier: stat: %q while matching glob pattern %q", err.Error(), glob)
}
if len(globMatched) == 0 && strings.ContainsAny(glob, "*?[") {
continue
}
// collect the matches
@ -1079,6 +1081,14 @@ func copierHandlerStat(req request, pm *fileutils.PatternMatcher) *response {
s.Results = nil
s.Error = fmt.Sprintf("copier: stat: %q: %v", glob, syscall.ENOENT)
}
stats = append(stats, &s)
}
// no matches -> error
if len(stats) == 0 {
s := StatsForGlob{
Error: fmt.Sprintf("copier: stat: %q: %v", req.Globs, syscall.ENOENT),
}
stats = append(stats, &s)
}
return &response{Stat: statResponse{Globs: stats}}
}

View File

@ -372,7 +372,7 @@ func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) err
StripSetgidBit: stripSetgid,
}
if err := s.builder.Add(copy.Dest, copy.Download, options, sources...); err != nil {
return errors.Wrapf(err, "error adding sources %v", sources)
return err
}
}
return nil

View File

@ -2811,3 +2811,10 @@ _EOF
! expect_output --substring '\-\-build-arg SECRET=<VALUE>'
! expect_output --substring '\-\-build-arg NEWSECRET=<VALUE>'
}
@test "bud with .dockerignore - 3" {
run_buildah bud -t test --signature-policy ${TESTSDIR}/policy.json ${TESTSDIR}/bud/copy-globs
run_buildah bud -t test2 -f Containerfile.missing --signature-policy ${TESTSDIR}/policy.json ${TESTSDIR}/bud/copy-globs
run_buildah 125 bud -t test3 -f Containerfile.bad --signature-policy ${TESTSDIR}/policy.json ${TESTSDIR}/bud/copy-globs
expect_output --substring 'error building.*"COPY \*foo /testdir".*no such file or directory'
}

View File

@ -0,0 +1,3 @@
FROM scratch
# *txt exists so should succeed
COPY *.txt /testdir

View File

@ -0,0 +1,3 @@
FROM scratch
# No match so should fail
COPY *foo /testdir

View File

@ -0,0 +1,3 @@
FROM scratch
# No match for *foo, but *txt exists so should succeed
COPY *foo *.txt /testdir

View File

@ -0,0 +1,2 @@
FROM php:7.2
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

View File

View File

View File

@ -1925,6 +1925,36 @@ var internalTestCases = []testCase{
shouldFailAt: 2,
},
{
name: "copy-multiple-missing-file-with-glob",
dockerfileContents: strings.Join([]string{
"FROM scratch",
"COPY file-z.txt subdir-* subdir/",
}, "\n"),
contextDir: "dockerignore/populated",
shouldFailAt: 2,
},
{
name: "copy-multiple-missing-file-with-nomatch-on-glob",
dockerfileContents: strings.Join([]string{
"FROM scratch",
"COPY missing* subdir/",
}, "\n"),
contextDir: "dockerignore/populated",
shouldFailAt: 2,
},
{
name: "copy-multiple-some-missing-glob",
dockerfileContents: strings.Join([]string{
"FROM scratch",
"COPY file-a.txt subdir-* file-?.txt missing* subdir/",
}, "\n"),
contextDir: "dockerignore/populated",
fsSkip: []string{"(dir):subdir:mtime"},
},
{
name: "file-in-workdir-in-other-stage",
dockerfileContents: strings.Join([]string{