Docker does not apply .dockerignore to a build context sent as a tar, so upaas sent every file in the clone. The build now reads the ignore file as docker build does, <Dockerfile>.dockerignore next to the Dockerfile if there is one, otherwise .dockerignore at the root, with the ignorefile reader of moby/patternmatcher, and passes its patterns as exclude patterns. As the docker command line does, the Dockerfile and .dockerignore are never left out. An ignore file that cannot be read, or a malformed pattern, fails the build. Model: opus-5-5
63 lines
1.7 KiB
Go
63 lines
1.7 KiB
Go
package docker
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/moby/patternmatcher"
|
|
"github.com/moby/patternmatcher/ignorefile"
|
|
)
|
|
|
|
// readDockerignore returns the patterns of the files to leave out of the
|
|
// build context in contextDir, read as docker build reads them for the
|
|
// Dockerfile at dockerfile, a path inside contextDir: from
|
|
// <dockerfile>.dockerignore next to the Dockerfile if there is one, otherwise
|
|
// from .dockerignore at the root of the context. Without either file there
|
|
// are no patterns.
|
|
func readDockerignore(contextDir, dockerfile string) ([]string, error) {
|
|
if dockerfile == "" {
|
|
dockerfile = "Dockerfile" // what Docker builds when none is named
|
|
}
|
|
|
|
name := dockerfile + ".dockerignore"
|
|
|
|
file, err := os.Open(filepath.Join(contextDir, name))
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
name = ".dockerignore"
|
|
file, err = os.Open(filepath.Join(contextDir, name))
|
|
}
|
|
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
return nil, nil
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read %s: %w", name, err)
|
|
}
|
|
|
|
defer func() { _ = file.Close() }()
|
|
|
|
excludes, err := ignorefile.ReadAll(file)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read %s: %w", name, err)
|
|
}
|
|
|
|
// Like the docker command line, never leave out .dockerignore or the
|
|
// Dockerfile: Docker reads the Dockerfile from the context.
|
|
for _, keep := range []string{".dockerignore", filepath.ToSlash(dockerfile)} {
|
|
excluded, err := patternmatcher.MatchesOrParentMatches(keep, excludes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid pattern in %s: %w", name, err)
|
|
}
|
|
|
|
if excluded {
|
|
excludes = append(excludes, "!"+keep)
|
|
}
|
|
}
|
|
|
|
return excludes, nil
|
|
}
|