Skip to content

Commit

Permalink
bug: Update getFileFilter to include parent folders
Browse files Browse the repository at this point in the history
- The `include` directive when specified with a file inside a
  folder `testdir/testfile` did not pass the parent folder to
  the builder image, which led to the folder being created by
  docker instead pack causing the permissions of the folder
  to be `cnb`.
- This PR fixes the include logic to get parent folders and
  add them to the file filter, so they get created via pack.

Signed-off-by: Nitish Gupta <[email protected]>
  • Loading branch information
imnitishng committed May 11, 2022
1 parent bed572e commit a76e5f8
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 2 deletions.
27 changes: 25 additions & 2 deletions pkg/client/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,13 +420,36 @@ func getFileFilter(descriptor projectTypes.Descriptor) (func(string) bool, error
}, nil
}
if len(descriptor.Build.Include) > 0 {
includes := ignore.CompileIgnoreLines(descriptor.Build.Include...)
includeEntries := []string{}
for _, entry := range descriptor.Build.Include {
parentFolders, err := getParentDirs(entry)
for _, folder := range parentFolders {
includeEntries = append(includeEntries, "!"+folder+"/*")
includeEntries = append(includeEntries, folder)
}
if err != nil {
return nil, err
}
}
includePatterns := append(includeEntries, descriptor.Build.Include...)
includes := ignore.CompileIgnoreLines(includePatterns...)
return includes.MatchesPath, nil
}

return nil, nil
}

func getParentDirs(file string) ([]string, error) {
parent := filepath.Dir(file)
if parent == filepath.VolumeName(file)+`\` || parent == "/" || parent == "." {
return []string{}, nil
}
parentDirs, err := getParentDirs(parent)
if err != nil {
return nil, err
}
return append(parentDirs, parent), nil
}

func lifecycleImageSupported(builderOS string, lifecycleVersion *builder.Version) bool {
return lifecycleVersion.Equal(builder.VersionMustParse(prevLifecycleVersionSupportingImage)) ||
!lifecycleVersion.LessThan(semver.MustParse(minLifecycleVersionSupportingImage))
Expand Down
167 changes: 167 additions & 0 deletions pkg/client/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2508,6 +2508,167 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
})
})
})

when("#getFileFilter", func() {
it("project descriptor with include directive", func() {
toCheck := []fileFilterCompare{
{
inputType: "unnested files",
directiveInput: []string{"file1.txt", "file2.txt"},
patternOutputMap: map[string]bool{
"parent": false,
"file1.txt": true,
"file2.txt": true,
"parent/file1.txt": true,
"parent/file2.txt": true,
},
},
{
inputType: "unnested directories",
directiveInput: []string{"dir1", "dir2"},
patternOutputMap: map[string]bool{
"dir1": true,
"dir2": true,
"file1.txt": false,
"dir1/dir2": true,
"dir1/dir2/folder3": true,
"folder/dir1": true,
"dir1/file1.txt": true,
"folder/folder2/dir2": true,
"dir2/folder/file2.txt": true,
},
},
{
inputType: "single level nested files",
directiveInput: []string{"parent/file1.txt", "parent/file2.txt"},
patternOutputMap: map[string]bool{
"parent": true,
"file1.txt": false,
"file2.txt": false,
"parent/file1.txt": true,
"parent/file2.txt": true,
},
},
{
inputType: "double level nested files",
directiveInput: []string{"parent1/file1.txt", "parent1/parent2/file2.txt"},
patternOutputMap: map[string]bool{
"parent1": true,
"parent2": false,
"file1.txt": false,
"file2.txt": false,
"parent1/parent2": true,
"parent1/file1.txt": true,
"parent2/file2.txt": false,
"parent1/parent2/file2.txt": true,
},
},
{
inputType: "multi level nested files with same dir names",
directiveInput: []string{"parent/samename/diffname/samename/file1.txt"},
patternOutputMap: map[string]bool{
"parent": true,
"samename": false,
"diffname": false,
"file1.txt": false,
"parent/samename": true,
"samename/diffname": false,
"diffname/samename": false,
"samename/file1.txt": false,
"parent/samename/diffname": true,
"samename/diffname/samename": false,
"diffname/samename/file1.txt": false,
"parent/samename/diffname/samename": true,
"parent/samename/diffname/samename/file1.txt": true,
},
},
}

for _, checkEntry := range toCheck {
t.Logf("checking directive input type: %s", checkEntry.inputType)
fileFilter, err := getFileFilter(projectTypes.Descriptor{
Build: projectTypes.Build{
Include: checkEntry.directiveInput,
},
})
for pattern, expectedOutput := range checkEntry.patternOutputMap {
t.Logf("checking pattern %s", pattern)
h.AssertEq(t, fileFilter(pattern), expectedOutput)
}
h.AssertNil(t, err)
}
})

it("project descriptor with exclude directive", func() {
toCheck := []fileFilterCompare{
{
inputType: "unnested files",
directiveInput: []string{"file1.txt", "file2.txt"},
patternOutputMap: map[string]bool{
"parent": true,
"file1.txt": false,
"file2.txt": false,
"parent/file1.txt": false,
"parent/file2.txt": false,
},
},
{
inputType: "unnested directories",
directiveInput: []string{"dir1", "dir2"},
patternOutputMap: map[string]bool{
"dir1": false,
"dir2": false,
"file1.txt": true,
"dir1/dir2": false,
"dir1/dir2/folder3": false,
"folder/dir1": false,
"dir1/file1.txt": false,
"folder/folder2/dir2": false,
"dir2/folder/file2.txt": false,
},
},
{
inputType: "single level nested files",
directiveInput: []string{"parent/file1.txt", "parent/file2.txt"},
patternOutputMap: map[string]bool{
"parent": true,
"file1.txt": true,
"file2.txt": true,
"parent/file1.txt": false,
"parent/file2.txt": false,
},
},
{
inputType: "double level nested files",
directiveInput: []string{"parent1/file1.txt", "parent1/parent2/file2.txt"},
patternOutputMap: map[string]bool{
"parent1": true,
"parent2": true,
"file1.txt": true,
"file2.txt": true,
"parent1/parent2": true,
"parent1/file1.txt": false,
"parent2/file2.txt": true,
"parent1/parent2/file2.txt": false,
},
},
}

for _, checkEntry := range toCheck {
t.Logf("checking directive input type: %s", checkEntry.inputType)
fileFilter, err := getFileFilter(projectTypes.Descriptor{
Build: projectTypes.Build{
Exclude: checkEntry.directiveInput,
},
})
for pattern, expectedOutput := range checkEntry.patternOutputMap {
t.Logf("checking pattern: %s", pattern)
h.AssertEq(t, fileFilter(pattern), expectedOutput)
}
h.AssertNil(t, err)
}
})
})
}

func diffIDForFile(t *testing.T, path string) string {
Expand Down Expand Up @@ -2623,3 +2784,9 @@ func (f *executeFailsLifecycle) Execute(_ context.Context, opts build.LifecycleO
f.Opts = opts
return errors.New("")
}

type fileFilterCompare struct {
inputType string
directiveInput []string
patternOutputMap map[string]bool
}

0 comments on commit a76e5f8

Please sign in to comment.