Merge pull request #1577 from orisano/1576-improve-validate-context-directory

feat: improves ValidateContextDirectory performance
This commit is contained in:
Sebastiaan van Stijn 2019-04-01 13:22:27 +02:00 committed by GitHub
commit f28d078426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 1 deletions

View File

@ -41,6 +41,12 @@ func ValidateContextDirectory(srcPath string, excludes []string) error {
if err != nil {
return err
}
pm, err := fileutils.NewPatternMatcher(excludes)
if err != nil {
return err
}
return filepath.Walk(contextRoot, func(filePath string, f os.FileInfo, err error) error {
if err != nil {
if os.IsPermission(err) {
@ -55,7 +61,7 @@ func ValidateContextDirectory(srcPath string, excludes []string) error {
// skip this directory/file if it's not in the path, it won't get added to the context
if relFilePath, err := filepath.Rel(contextRoot, filePath); err != nil {
return err
} else if skip, err := fileutils.Matches(relFilePath, excludes); err != nil {
} else if skip, err := filepathMatches(pm, relFilePath); err != nil {
return err
} else if skip {
if f.IsDir() {
@ -81,6 +87,15 @@ func ValidateContextDirectory(srcPath string, excludes []string) error {
})
}
func filepathMatches(matcher *fileutils.PatternMatcher, file string) (bool, error) {
file = filepath.Clean(file)
if file == "." {
// Don't let them exclude everything, kind of silly.
return false, nil
}
return matcher.Matches(file)
}
// DetectArchiveReader detects whether the input stream is an archive or a
// Dockerfile and returns a buffered version of input, safe to consume in lieu
// of input. If an archive is detected, isArchive is set to true, and to false

View File

@ -12,6 +12,7 @@ import (
"testing"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/fileutils"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
@ -330,3 +331,86 @@ func TestDetectArchiveReader(t *testing.T) {
assert.Check(t, is.Equal(testcase.expected, isArchive), testcase.file)
}
}
func mustPatternMatcher(t *testing.T, patterns []string) *fileutils.PatternMatcher {
t.Helper()
pm, err := fileutils.NewPatternMatcher(patterns)
if err != nil {
t.Fatal("failed to construct pattern matcher: ", err)
}
return pm
}
func TestWildcardMatches(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"*"}), "fileutils.go")
if !match {
t.Errorf("failed to get a wildcard match, got %v", match)
}
}
// A simple pattern match should return true.
func TestPatternMatches(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"*.go"}), "fileutils.go")
if !match {
t.Errorf("failed to get a match, got %v", match)
}
}
// An exclusion followed by an inclusion should return true.
func TestExclusionPatternMatchesPatternBefore(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"!fileutils.go", "*.go"}), "fileutils.go")
if !match {
t.Errorf("failed to get true match on exclusion pattern, got %v", match)
}
}
// A folder pattern followed by an exception should return false.
func TestPatternMatchesFolderExclusions(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"docs", "!docs/README.md"}), "docs/README.md")
if match {
t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
}
}
// A folder pattern followed by an exception should return false.
func TestPatternMatchesFolderWithSlashExclusions(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"docs/", "!docs/README.md"}), "docs/README.md")
if match {
t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
}
}
// A folder pattern followed by an exception should return false.
func TestPatternMatchesFolderWildcardExclusions(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"docs/*", "!docs/README.md"}), "docs/README.md")
if match {
t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
}
}
// A pattern followed by an exclusion should return false.
func TestExclusionPatternMatchesPatternAfter(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"*.go", "!fileutils.go"}), "fileutils.go")
if match {
t.Errorf("failed to get false match on exclusion pattern, got %v", match)
}
}
// A filename evaluating to . should return false.
func TestExclusionPatternMatchesWholeDirectory(t *testing.T) {
match, _ := filepathMatches(mustPatternMatcher(t, []string{"*.go"}), ".")
if match {
t.Errorf("failed to get false match on ., got %v", match)
}
}
// Matches with no patterns
func TestMatchesWithNoPatterns(t *testing.T) {
matches, err := filepathMatches(mustPatternMatcher(t, []string{}), "/any/path/there")
if err != nil {
t.Fatal(err)
}
if matches {
t.Fatalf("Should not have match anything")
}
}