Skip to content

Commit

Permalink
fix(staged-dockerfile): fix docker ignore path matcher
Browse files Browse the repository at this point in the history
Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
  • Loading branch information
ilya-lesikov committed Oct 17, 2022
1 parent 647700a commit c4b6cd5
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 107 deletions.
72 changes: 8 additions & 64 deletions pkg/build/image/build_context_archive.go
@@ -1,15 +1,12 @@
package image

import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/docker/docker/builder/dockerignore"

"github.com/werf/logboek"
"github.com/werf/werf/pkg/container_backend"
"github.com/werf/werf/pkg/context_manager"
Expand All @@ -36,17 +33,18 @@ type BuildContextArchive struct {
func (a *BuildContextArchive) Create(ctx context.Context, opts container_backend.BuildContextArchiveCreateOptions) error {
contextPathRelativeToGitWorkTree := filepath.Join(a.giterminismMgr.RelativeToGitProjectDir(), opts.ContextGitSubDir)

pathMatcher := path_matcher.NewPathMatcher(path_matcher.PathMatcherOptions{BasePath: contextPathRelativeToGitWorkTree})
if dockerIgnorePathMatcher, err := createDockerIgnorePathMatcher(ctx, a.giterminismMgr, opts.ContextGitSubDir, opts.DockerfileRelToContextPath); err != nil {
dockerIgnorePathMatcher, err := createDockerIgnorePathMatcher(ctx, a.giterminismMgr, opts.ContextGitSubDir, opts.DockerfileRelToContextPath)
if err != nil {
return fmt.Errorf("unable to create dockerignore path matcher: %w", err)
} else if dockerIgnorePathMatcher != nil {
pathMatcher = path_matcher.NewMultiPathMatcher(pathMatcher, dockerIgnorePathMatcher)
}

archive, err := a.giterminismMgr.LocalGitRepo().GetOrCreateArchive(ctx, git_repo.ArchiveOptions{
PathScope: contextPathRelativeToGitWorkTree,
PathMatcher: pathMatcher,
Commit: a.giterminismMgr.HeadCommit(),
PathScope: contextPathRelativeToGitWorkTree,
PathMatcher: path_matcher.NewMultiPathMatcher(path_matcher.NewPathMatcher(
path_matcher.PathMatcherOptions{BasePath: contextPathRelativeToGitWorkTree}),
dockerIgnorePathMatcher,
),
Commit: a.giterminismMgr.HeadCommit(),
})
if err != nil {
return fmt.Errorf("unable to get or create archive: %w", err)
Expand Down Expand Up @@ -107,57 +105,3 @@ func (a *BuildContextArchive) CleanupExtractedDir(ctx context.Context) {
logboek.Context(ctx).Warn().LogF("WARNING: unable to remove extracted context dir %q: %s", a.extractionDir, err)
}
}

// Might return nil.
func createDockerIgnorePathMatcher(ctx context.Context, giterminismMgr giterminism_manager.Interface, contextGitSubDir, dockerfileRelToContextPath string) (path_matcher.PathMatcher, error) {
dockerfileRelToGitPath := filepath.Join(contextGitSubDir, dockerfileRelToContextPath)

var dockerIgnorePatterns []string
for _, dockerIgnoreRelToContextPath := range []string{
dockerfileRelToContextPath + ".dockerignore",
".dockerignore",
} {
dockerIgnoreRelToGitPath := filepath.Join(contextGitSubDir, dockerIgnoreRelToContextPath)
if exist, err := giterminismMgr.FileReader().IsDockerignoreExistAnywhere(ctx, dockerIgnoreRelToGitPath); err != nil {
return nil, err
} else if !exist {
continue
}

dockerIgnore, err := giterminismMgr.FileReader().ReadDockerignore(ctx, dockerIgnoreRelToGitPath)
if err != nil {
return nil, err
}

r := bytes.NewReader(dockerIgnore)
dockerIgnorePatterns, err = dockerignore.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("unable to read %q file: %w", dockerIgnoreRelToContextPath, err)
}

break
}

if dockerIgnorePatterns == nil {
return nil, nil
}

dockerIgnorePathMatcher := path_matcher.NewPathMatcher(path_matcher.PathMatcherOptions{
BasePath: filepath.Join(giterminismMgr.RelativeToGitProjectDir(), contextGitSubDir),
DockerignorePatterns: dockerIgnorePatterns,
})

if !dockerIgnorePathMatcher.IsPathMatched(dockerfileRelToGitPath) {
logboek.Context(ctx).Warn().LogLn("WARNING: There is no way to ignore the Dockerfile due to docker limitation when building an image for a compressed context that reads from STDIN.")
logboek.Context(ctx).Warn().LogF("WARNING: To hide this message, remove the Dockerfile ignore rule or add an exception rule.\n")

exceptionRule := "!" + dockerfileRelToContextPath
dockerIgnorePatterns = append(dockerIgnorePatterns, exceptionRule)
dockerIgnorePathMatcher = path_matcher.NewPathMatcher(path_matcher.PathMatcherOptions{
BasePath: filepath.Join(giterminismMgr.RelativeToGitProjectDir(), contextGitSubDir),
DockerignorePatterns: dockerIgnorePatterns,
})
}

return dockerIgnorePathMatcher, nil
}
99 changes: 56 additions & 43 deletions pkg/build/image/dockerfile.go
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/werf/werf/pkg/dockerfile"
"github.com/werf/werf/pkg/dockerfile/frontend"
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
"github.com/werf/werf/pkg/giterminism_manager"
"github.com/werf/werf/pkg/path_matcher"
"github.com/werf/werf/pkg/util"
)
Expand Down Expand Up @@ -121,54 +122,17 @@ func mapLegacyDockerfileToImage(ctx context.Context, dockerfileImageConfig *conf
}
}

dockerIgnorePathMatcher, err := createDockerIgnorePathMatcher(ctx, opts.GiterminismManager, dockerfileImageConfig.Context, dockerfileImageConfig.Dockerfile)
if err != nil {
return nil, fmt.Errorf("unable to create dockerignore path matcher: %w", err)
}

relDockerfilePath := filepath.Join(dockerfileImageConfig.Context, dockerfileImageConfig.Dockerfile)
dockerfileData, err := opts.GiterminismManager.FileReader().ReadDockerfile(ctx, relDockerfilePath)
if err != nil {
return nil, err
}

var relDockerignorePath string
var dockerignorePatterns []string
for _, relContextDockerignorePath := range []string{
dockerfileImageConfig.Dockerfile + ".dockerignore",
".dockerignore",
} {
relDockerignorePath = filepath.Join(dockerfileImageConfig.Context, relContextDockerignorePath)
if exist, err := opts.GiterminismManager.FileReader().IsDockerignoreExistAnywhere(ctx, relDockerignorePath); err != nil {
return nil, err
} else if exist {
dockerignoreData, err := opts.GiterminismManager.FileReader().ReadDockerignore(ctx, relDockerignorePath)
if err != nil {
return nil, err
}

r := bytes.NewReader(dockerignoreData)
dockerignorePatterns, err = dockerignore.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("unable to read %q file: %w", relContextDockerignorePath, err)
}

break
}
}

dockerignorePathMatcher := path_matcher.NewPathMatcher(path_matcher.PathMatcherOptions{
BasePath: filepath.Join(opts.GiterminismManager.RelativeToGitProjectDir(), dockerfileImageConfig.Context),
DockerignorePatterns: dockerignorePatterns,
})

if !dockerignorePathMatcher.IsPathMatched(relDockerfilePath) {
exceptionRule := "!" + dockerfileImageConfig.Dockerfile
logboek.Context(ctx).Warn().LogLn("WARNING: There is no way to ignore the Dockerfile due to docker limitation when building an image for a compressed context that reads from STDIN.")
logboek.Context(ctx).Warn().LogF("WARNING: To hide this message, remove the Dockerfile ignore rule from the %q or add an exception rule %q.\n", relDockerignorePath, exceptionRule)

dockerignorePatterns = append(dockerignorePatterns, exceptionRule)
dockerignorePathMatcher = path_matcher.NewPathMatcher(path_matcher.PathMatcherOptions{
BasePath: filepath.Join(opts.GiterminismManager.RelativeToGitProjectDir(), dockerfileImageConfig.Context),
DockerignorePatterns: dockerignorePatterns,
})
}

p, err := parser.Parse(bytes.NewReader(dockerfileData))
if err != nil {
return nil, err
Expand Down Expand Up @@ -211,7 +175,7 @@ func mapLegacyDockerfileToImage(ctx context.Context, dockerfileImageConfig *conf
dockerfileImageConfig.SSH,
),
ds,
stage.NewContextChecksum(dockerignorePathMatcher),
stage.NewContextChecksum(dockerIgnorePathMatcher),
baseStageOptions,
dockerfileImageConfig.Dependencies,
)
Expand All @@ -222,3 +186,52 @@ func mapLegacyDockerfileToImage(ctx context.Context, dockerfileImageConfig *conf

return img, nil
}

func createDockerIgnorePathMatcher(ctx context.Context, giterminismMgr giterminism_manager.Interface, contextGitSubDir, dockerfileRelToContextPath string) (path_matcher.PathMatcher, error) {
dockerfileRelToGitPath := filepath.Join(contextGitSubDir, dockerfileRelToContextPath)

var dockerIgnorePatterns []string
for _, dockerIgnoreRelToContextPath := range []string{
dockerfileRelToContextPath + ".dockerignore",
".dockerignore",
} {
dockerIgnoreRelToGitPath := filepath.Join(contextGitSubDir, dockerIgnoreRelToContextPath)
if exist, err := giterminismMgr.FileReader().IsDockerignoreExistAnywhere(ctx, dockerIgnoreRelToGitPath); err != nil {
return nil, err
} else if !exist {
continue
}

dockerIgnore, err := giterminismMgr.FileReader().ReadDockerignore(ctx, dockerIgnoreRelToGitPath)
if err != nil {
return nil, err
}

r := bytes.NewReader(dockerIgnore)
dockerIgnorePatterns, err = dockerignore.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("unable to read %q file: %w", dockerIgnoreRelToContextPath, err)
}

break
}

dockerIgnorePathMatcher := path_matcher.NewPathMatcher(path_matcher.PathMatcherOptions{
BasePath: filepath.Join(giterminismMgr.RelativeToGitProjectDir(), contextGitSubDir),
DockerignorePatterns: dockerIgnorePatterns,
})

if !dockerIgnorePathMatcher.IsPathMatched(dockerfileRelToGitPath) {
logboek.Context(ctx).Warn().LogLn("WARNING: There is no way to ignore the Dockerfile due to docker limitation when building an image for a compressed context that reads from STDIN.")
logboek.Context(ctx).Warn().LogF("WARNING: To hide this message, remove the Dockerfile ignore rule or add an exception rule.\n")

exceptionRule := "!" + dockerfileRelToContextPath
dockerIgnorePatterns = append(dockerIgnorePatterns, exceptionRule)
dockerIgnorePathMatcher = path_matcher.NewPathMatcher(path_matcher.PathMatcherOptions{
BasePath: filepath.Join(giterminismMgr.RelativeToGitProjectDir(), contextGitSubDir),
DockerignorePatterns: dockerIgnorePatterns,
})
}

return dockerIgnorePathMatcher, nil
}

0 comments on commit c4b6cd5

Please sign in to comment.