From 5cf91099444673fda65528be9c0a0e6d85fdcb10 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Tue, 24 Jan 2023 18:14:20 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20TOML=20extender?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 1 + go.sum | 2 + pkg/extras/extender.go | 82 +++++++++++++++++++++++++++++++ pkg/extras/extender_test.go | 45 +++++++++++++++++ pkg/extras/extendertype_string.go | 5 +- 5 files changed, 133 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 1b0fb6c..388b4b0 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 github.com/pjbgf/sha1cd v0.2.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 836e3d7..eb4f259 100644 --- a/go.sum +++ b/go.sum @@ -129,6 +129,8 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pjbgf/sha1cd v0.2.3 h1:uKQP/7QOzNtKYH7UTohZLcjF5/55EnTw0jO/Ru4jZwI= github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/pkg/extras/extender.go b/pkg/extras/extender.go index 509f2db..2853c3c 100644 --- a/pkg/extras/extender.go +++ b/pkg/extras/extender.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" + "github.com/pelletier/go-toml/v2" "golang.org/x/text/cases" "golang.org/x/text/language" "sigs.k8s.io/kustomize/kyaml/errors" @@ -48,6 +49,7 @@ const ( Base64Extender RegexExtender JsonExtender + TomlExtender ) var stringToExtenderTypeMap map[string]ExtenderType @@ -361,6 +363,85 @@ func NewJsonExtender() Extender { return &jsonExtender{} } +/////// +// TOML +/////// + +type tomlExtender struct { + node *yaml.RNode +} + +func (e *tomlExtender) SetPayload(payload []byte) error { + + m := map[string]interface{}{} + err := toml.Unmarshal(payload, &m) + if err != nil { + return errors.WrapPrefixf(err, "while un-marshalling toml") + } + + e.node, err = yaml.FromMap(m) + if err != nil { + return errors.WrapPrefixf(err, "while converting into yaml") + } + + return nil +} + +func getTOMLPayload(node *yaml.RNode) ([]byte, error) { + m, err := node.Map() + if err != nil { + return nil, errors.WrapPrefixf(err, "while encoding to map") + } + return toml.Marshal(m) +} + +func (e *tomlExtender) GetPayload() ([]byte, error) { + return getTOMLPayload(e.node) +} + +func (e *tomlExtender) Get(path []string) ([]byte, error) { + targetFields, err := Lookup(e.node, path) + if err != nil { + return nil, errors.WrapPrefixf(err, "error fetching elements in replacement target") + } + + if len(targetFields) > 1 { + return nil, fmt.Errorf("path %s returned %d items. Expected one", strings.Join(path, "."), len(targetFields)) + } + + target := targetFields[0] + if target.YNode().Kind == yaml.ScalarNode { + return []byte(target.YNode().Value), nil + } + + return getTOMLPayload(target) +} + +func (e *tomlExtender) Set(path []string, value any) error { + + targetFields, err := Lookup(e.node, path) + if err != nil { + return fmt.Errorf("error fetching elements in replacement target: %w", err) + } + + for _, t := range targetFields { + if t.YNode().Kind == yaml.ScalarNode { + t.YNode().Value = string(GetByteValue(value)) + } else { + if v, ok := value.(*yaml.Node); ok { + t.SetYNode(v) + } else { + return fmt.Errorf("setting non toml object in place of object of type %s at path %s", t.YNode().Tag, strings.Join(path, ".")) + } + } + } + return nil +} + +func NewTomlExtender() Extender { + return &tomlExtender{} +} + //////////// // Factories //////////// @@ -370,6 +451,7 @@ var ExtenderFactories = map[ExtenderType]func() Extender{ Base64Extender: NewBase64Extender, RegexExtender: NewRegexExtender, JsonExtender: NewJsonExtender, + TomlExtender: NewTomlExtender, } func (path *ExtendedSegment) Extender(payload []byte) (Extender, error) { diff --git a/pkg/extras/extender_test.go b/pkg/extras/extender_test.go index b19973e..a9661c6 100644 --- a/pkg/extras/extender_test.go +++ b/pkg/extras/extender_test.go @@ -373,6 +373,51 @@ func (s *ExtenderTestSuite) TestJsonArrayExtender() { require.Equal("deploy/citest", string(value), "error fetching changed value") } +func (s *ExtenderTestSuite) TestTomlExtender() { + require := s.Require() + source := ` +uninode = true +[common] +targetRevision = 'main' +[apps] +enabled = true +` + expected := `uninode = true + +[apps] +enabled = true + +[common] +targetRevision = 'deploy/citest' +` + + p := `!!toml.common.targetRevision` + path := kyaml_utils.SmarterPathSplitter(p, ".") + + extensions := []*ExtendedSegment{} + prefix, err := splitExtendedPath(path, &extensions) + require.NoError(err) + require.Len(prefix, 0, "There should be no prefix") + require.Len(extensions, 1, "There should be 2 extensions") + require.Equal("toml", extensions[0].Encoding, "The first extension should be toml") + + tomlXP := extensions[0] + tomlExt, err := tomlXP.Extender([]byte(source)) + require.NoError(err) + value, err := tomlExt.Get(tomlXP.Path) + require.NoError(err) + require.Equal("main", string(value), "error fetching value") + require.NoError(tomlExt.Set(tomlXP.Path, []byte("deploy/citest"))) + + modified, err := tomlExt.GetPayload() + require.NoError(err) + require.Equal(expected, string(modified), "final toml") + + value, err = tomlExt.Get(tomlXP.Path) + require.NoError(err) + require.Equal("deploy/citest", string(value), "error fetching changed value") +} + func TestExtender(t *testing.T) { suite.Run(t, new(ExtenderTestSuite)) } diff --git a/pkg/extras/extendertype_string.go b/pkg/extras/extendertype_string.go index 4188249..0988f23 100644 --- a/pkg/extras/extendertype_string.go +++ b/pkg/extras/extendertype_string.go @@ -13,11 +13,12 @@ func _() { _ = x[Base64Extender-2] _ = x[RegexExtender-3] _ = x[JsonExtender-4] + _ = x[TomlExtender-5] } -const _ExtenderType_name = "UnknownYamlExtenderBase64ExtenderRegexExtenderJsonExtender" +const _ExtenderType_name = "UnknownYamlExtenderBase64ExtenderRegexExtenderJsonExtenderTomlExtender" -var _ExtenderType_index = [...]uint8{0, 7, 19, 33, 46, 58} +var _ExtenderType_index = [...]uint8{0, 7, 19, 33, 46, 58, 70} func (i ExtenderType) String() string { if i < 0 || i >= ExtenderType(len(_ExtenderType_index)-1) {