diff --git a/api/filters/fieldspec/fieldspec.go b/api/filters/fieldspec/fieldspec.go index 00026b923..f7af2bb5b 100644 --- a/api/filters/fieldspec/fieldspec.go +++ b/api/filters/fieldspec/fieldspec.go @@ -7,6 +7,7 @@ import ( "strings" "sigs.k8s.io/kustomize/api/filters/filtersutil" + "sigs.k8s.io/kustomize/api/internal/utils" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/yaml" @@ -37,7 +38,7 @@ func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) { if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil { return obj, errors.Wrap(err) } - fltr.path = splitPath(fltr.FieldSpec.Path) + fltr.path = utils.PathSplitter(fltr.FieldSpec.Path) if err := fltr.filter(obj); err != nil { s, _ := obj.String() return nil, errors.WrapPrefixf(err, @@ -165,18 +166,3 @@ func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) (bool, error) { return true, nil } - -func splitPath(path string) []string { - ps := strings.Split(path, "/") - var res []string - res = append(res, ps[0]) - for i := 1; i < len(ps); i++ { - lastIndex := len(res) - 1 - if strings.HasSuffix(res[lastIndex], "\\") { - res[lastIndex] = strings.TrimSuffix(res[lastIndex], "\\") + "/" + ps[i] - } else { - res = append(res, ps[i]) - } - } - return res -} diff --git a/api/internal/utils/pathsplitter.go b/api/internal/utils/pathsplitter.go new file mode 100644 index 000000000..c8d2f3342 --- /dev/null +++ b/api/internal/utils/pathsplitter.go @@ -0,0 +1,22 @@ +// Copyright 2021 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import "strings" + +// PathSplitter splits a slash delimited string, permitting escaped slashes. +func PathSplitter(path string) []string { + ps := strings.Split(path, "/") + var res []string + res = append(res, ps[0]) + for i := 1; i < len(ps); i++ { + last := len(res) - 1 + if strings.HasSuffix(res[last], `\`) { + res[last] = strings.TrimSuffix(res[last], `\`) + "/" + ps[i] + } else { + res = append(res, ps[i]) + } + } + return res +} diff --git a/api/internal/utils/pathsplitter_test.go b/api/internal/utils/pathsplitter_test.go new file mode 100644 index 000000000..9b52c3806 --- /dev/null +++ b/api/internal/utils/pathsplitter_test.go @@ -0,0 +1,49 @@ +// Copyright 2021 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package utils_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + . "sigs.k8s.io/kustomize/api/internal/utils" +) + +func TestPathSplitter(t *testing.T) { + for _, tc := range []struct { + exp []string + path string + }{ + { + path: "", + exp: []string{""}, + }, + { + path: "s", + exp: []string{"s"}, + }, + { + path: "a/b/c", + exp: []string{"a", "b", "c"}, + }, + { + path: `a/b[]/c`, + exp: []string{"a", "b[]", "c"}, + }, + { + path: `a/b\/c/d\/e/f`, + exp: []string{"a", "b/c", "d/e", "f"}, + }, + { + // The actual reason for this. + path: `metadata/annotations/nginx.ingress.kubernetes.io\/auth-secret`, + exp: []string{ + "metadata", + "annotations", + "nginx.ingress.kubernetes.io/auth-secret"}, + }, + } { + assert.Equal(t, tc.exp, PathSplitter(tc.path)) + } +} diff --git a/api/types/fieldspec.go b/api/types/fieldspec.go index e5836aa1c..f5b711ee5 100644 --- a/api/types/fieldspec.go +++ b/api/types/fieldspec.go @@ -5,7 +5,6 @@ package types import ( "fmt" - "strings" "sigs.k8s.io/kustomize/api/resid" ) @@ -34,11 +33,6 @@ type FieldSpec struct { CreateIfNotPresent bool `json:"create,omitempty" yaml:"create,omitempty"` } -const ( - escapedForwardSlash = "\\/" - tempSlashReplacement = "???" -) - func (fs FieldSpec) String() string { return fmt.Sprintf( "%s:%v:%s", fs.Gvk.String(), fs.CreateIfNotPresent, fs.Path) @@ -49,34 +43,6 @@ func (fs FieldSpec) effectivelyEquals(other FieldSpec) bool { return fs.IsSelected(&other.Gvk) && fs.Path == other.Path } -// PathSlice converts the path string to a slice of strings, -// separated by a '/'. Forward slash can be contained in a -// fieldname. such as ingress.kubernetes.io/auth-secret in -// Ingress annotations. To deal with this special case, the -// path to this field should be formatted as -// -// metadata/annotations/ingress.kubernetes.io\/auth-secret -// -// Then PathSlice will return -// -// []string{ -// "metadata", -// "annotations", -// "ingress.auth-secretkubernetes.io/auth-secret" -// } -func (fs FieldSpec) PathSlice() []string { - if !strings.Contains(fs.Path, escapedForwardSlash) { - return strings.Split(fs.Path, "/") - } - s := strings.Replace(fs.Path, escapedForwardSlash, tempSlashReplacement, -1) - paths := strings.Split(s, "/") - var result []string - for _, path := range paths { - result = append(result, strings.Replace(path, tempSlashReplacement, "/", -1)) - } - return result -} - type FsSlice []FieldSpec func (s FsSlice) Len() int { return len(s) } diff --git a/api/types/fieldspec_test.go b/api/types/fieldspec_test.go index 58282b6a1..94c400658 100644 --- a/api/types/fieldspec_test.go +++ b/api/types/fieldspec_test.go @@ -13,30 +13,6 @@ import ( . "sigs.k8s.io/kustomize/api/types" ) -func TestPathSlice(t *testing.T) { - type path struct { - input string - parsed []string - } - paths := []path{ - { - input: "spec/metadata/annotations", - parsed: []string{"spec", "metadata", "annotations"}, - }, - { - input: `metadata/annotations/nginx.ingress.kubernetes.io\/auth-secret`, - parsed: []string{"metadata", "annotations", "nginx.ingress.kubernetes.io/auth-secret"}, - }, - } - for _, p := range paths { - fs := FieldSpec{Path: p.input} - actual := fs.PathSlice() - if !reflect.DeepEqual(actual, p.parsed) { - t.Fatalf("expected %v, but got %v", p.parsed, actual) - } - } -} - var mergeTests = []struct { name string original FsSlice