fix: paths deduplication while resolving symlinks (#2504)

Closes #2381
This commit is contained in:
Fedor V 2023-05-29 11:37:20 +03:00 committed by GitHub
parent 43d2eafcf2
commit 90fe22bc2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 6 deletions

View File

@ -783,15 +783,51 @@ func filesToSave(deps []string) ([]string, error) {
}
}
// remove duplicates
deduped := deduplicatePaths(srcFiles)
return deduped, nil
}
// deduplicatePaths returns a deduplicated slice of shortest paths
// For example {"usr/lib", "usr/lib/ssl"} will return only {"usr/lib"}
func deduplicatePaths(paths []string) []string {
type node struct {
children map[string]*node
value bool
}
root := &node{children: make(map[string]*node)}
// Create a tree marking all present paths
for _, f := range paths {
parts := strings.Split(f, "/")
current := root
for i := 0; i < len(parts)-1; i++ {
part := parts[i]
if _, ok := current.children[part]; !ok {
current.children[part] = &node{children: make(map[string]*node)}
}
current = current.children[part]
}
current.children[parts[len(parts)-1]] = &node{children: make(map[string]*node), value: true}
}
// Collect all paths
deduped := []string{}
m := map[string]struct{}{}
for _, f := range srcFiles {
if _, ok := m[f]; !ok {
deduped = append(deduped, f)
m[f] = struct{}{}
var traverse func(*node, string)
traverse = func(n *node, path string) {
if n.value {
deduped = append(deduped, strings.TrimPrefix(path, "/"))
return
}
for k, v := range n.children {
traverse(v, path+"/"+k)
}
}
return deduped, nil
traverse(root, "")
return deduped
}
func fetchExtraStages(stages []config.KanikoStage, opts *config.KanikoOptions) error {

View File

@ -468,6 +468,41 @@ func Test_filesToSave(t *testing.T) {
}
}
func TestDeduplicatePaths(t *testing.T) {
tests := []struct {
name string
input []string
want []string
}{
{
name: "no duplicates",
input: []string{"file1.txt", "file2.txt", "usr/lib"},
want: []string{"file1.txt", "file2.txt", "usr/lib"},
},
{
name: "duplicates",
input: []string{"file1.txt", "file2.txt", "file2.txt", "usr/lib"},
want: []string{"file1.txt", "file2.txt", "usr/lib"},
},
{
name: "duplicates with paths",
input: []string{"file1.txt", "file2.txt", "file2.txt", "usr/lib", "usr/lib/ssl"},
want: []string{"file1.txt", "file2.txt", "usr/lib"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := deduplicatePaths(tt.input)
sort.Strings(tt.want)
sort.Strings(got)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("TestDeduplicatePaths() = %v, want %v", got, tt.want)
}
})
}
}
func TestInitializeConfig(t *testing.T) {
tests := []struct {
description string