From 14055848925df8d38e54f2b7fdd8442d6a360c40 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Thu, 11 Jun 2020 13:57:13 +1000 Subject: [PATCH] New,Update now support anchors and aliases --- cmd/constant.go | 2 ++ cmd/new.go | 2 ++ cmd/new_test.go | 24 ++++++++++++++++++++++++ cmd/utils.go | 4 ++-- cmd/write.go | 2 ++ pkg/yqlib/lib.go | 2 +- pkg/yqlib/update_navigation_strategy.go | 2 ++ pkg/yqlib/value_parser.go | 14 ++++++++++---- pkg/yqlib/value_parser_test.go | 17 ++++++++++++++--- 9 files changed, 59 insertions(+), 10 deletions(-) diff --git a/cmd/constant.go b/cmd/constant.go index b148f121..1b83a265 100644 --- a/cmd/constant.go +++ b/cmd/constant.go @@ -10,6 +10,8 @@ var printMode = "v" var printLength = false var unwrapScalar = true var customStyle = "" +var anchorName = "" +var makeAlias = false var stripComments = false var collectIntoArray = false var writeInplace = false diff --git a/cmd/new.go b/cmd/new.go index 7f665fda..ebe018a3 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -29,6 +29,8 @@ Note that you can give a create script to perform more sophisticated yaml. This cmdNew.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for creating yaml") cmdNew.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)") cmdNew.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged") + cmdNew.PersistentFlags().StringVarP(&anchorName, "anchorName", "", "", "anchor name") + cmdNew.PersistentFlags().BoolVarP(&makeAlias, "makeAlias", "", false, "create an alias using the value as the anchor name") return cmdNew } diff --git a/cmd/new_test.go b/cmd/new_test.go index de53020a..4697e8da 100644 --- a/cmd/new_test.go +++ b/cmd/new_test.go @@ -18,6 +18,30 @@ func TestNewCmd(t *testing.T) { test.AssertResult(t, expectedOutput, result.Output) } +func TestNewAnchorCmd(t *testing.T) { + cmd := getRootCommand() + result := test.RunCmd(cmd, "new b.c 3 --anchorName=fred") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `b: + c: &fred 3 +` + test.AssertResult(t, expectedOutput, result.Output) +} + +func TestNewAliasCmd(t *testing.T) { + cmd := getRootCommand() + result := test.RunCmd(cmd, "new b.c foo --makeAlias") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `b: + c: *foo +` + test.AssertResult(t, expectedOutput, result.Output) +} + func TestNewArrayCmd(t *testing.T) { cmd := getRootCommand() result := test.RunCmd(cmd, "new b[0] 3") diff --git a/cmd/utils.go b/cmd/utils.go index f9b032e9..0534d969 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -501,13 +501,13 @@ func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string) log.Debug("args %v", args) log.Debug("path %v", args[expectedArgs-2]) log.Debug("Value %v", args[expectedArgs-1]) - updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse(args[expectedArgs-1], customTag, customStyle), Overwrite: true} + updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse(args[expectedArgs-1], customTag, customStyle, anchorName, makeAlias), Overwrite: true} } else if len(args) == expectedArgs-1 { // don't update the value updateCommands = make([]yqlib.UpdateCommand, 1) log.Debug("args %v", args) log.Debug("path %v", args[expectedArgs-2]) - updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse("", customTag, customStyle), Overwrite: true, DontUpdateNodeValue: true} + updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse("", customTag, customStyle, anchorName, makeAlias), Overwrite: true, DontUpdateNodeValue: true} } else { return nil, errors.New(badArgsMessage) } diff --git a/cmd/write.go b/cmd/write.go index 3ef5949e..052b48c5 100644 --- a/cmd/write.go +++ b/cmd/write.go @@ -47,6 +47,8 @@ format is list of update commands (update or delete) like so: cmdWrite.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)") cmdWrite.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") cmdWrite.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged") + cmdWrite.PersistentFlags().StringVarP(&anchorName, "anchorName", "", "", "anchor name") + cmdWrite.PersistentFlags().BoolVarP(&makeAlias, "makeAlias", "", false, "create an alias using the value as the anchor name") return cmdWrite } diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index 8a1c8093..90682186 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -48,7 +48,7 @@ func DebugNode(value *yaml.Node) { log.Error("Error debugging node, %v", errorEncoding.Error()) } encoder.Close() - log.Debug("Tag: %v, Kind: %v", value.Tag, KindString(value.Kind)) + log.Debug("Tag: %v, Kind: %v, Anchor: %v", value.Tag, KindString(value.Kind), value.Anchor) log.Debug("%v", buf.String()) } } diff --git a/pkg/yqlib/update_navigation_strategy.go b/pkg/yqlib/update_navigation_strategy.go index e90c7bdb..99455925 100644 --- a/pkg/yqlib/update_navigation_strategy.go +++ b/pkg/yqlib/update_navigation_strategy.go @@ -31,6 +31,8 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi node.Kind = changesToApply.Kind node.Style = changesToApply.Style node.Content = changesToApply.Content + node.Anchor = changesToApply.Anchor + node.Alias = changesToApply.Alias node.HeadComment = changesToApply.HeadComment node.LineComment = changesToApply.LineComment node.FootComment = changesToApply.FootComment diff --git a/pkg/yqlib/value_parser.go b/pkg/yqlib/value_parser.go index 9c7d517b..6dee7400 100644 --- a/pkg/yqlib/value_parser.go +++ b/pkg/yqlib/value_parser.go @@ -5,7 +5,7 @@ import ( ) type ValueParser interface { - Parse(argument string, customTag string, customStyle string) *yaml.Node + Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node } type valueParser struct { @@ -15,7 +15,7 @@ func NewValueParser() ValueParser { return &valueParser{} } -func (v *valueParser) Parse(argument string, customTag string, customStyle string) *yaml.Node { +func (v *valueParser) Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node { var style yaml.Style if customStyle == "tagged" { style = yaml.TaggedStyle @@ -32,9 +32,15 @@ func (v *valueParser) Parse(argument string, customTag string, customStyle strin } else if customStyle != "" { log.Error("Unknown style %v, ignoring", customStyle) } - if argument == "[]" { return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode, Style: style} } - return &yaml.Node{Value: argument, Tag: customTag, Kind: yaml.ScalarNode, Style: style} + + kind := yaml.ScalarNode + + if createAlias { + kind = yaml.AliasNode + } + + return &yaml.Node{Value: argument, Tag: customTag, Kind: kind, Style: style, Anchor: anchorName} } diff --git a/pkg/yqlib/value_parser_test.go b/pkg/yqlib/value_parser_test.go index 130bf87d..a21a6ec1 100644 --- a/pkg/yqlib/value_parser_test.go +++ b/pkg/yqlib/value_parser_test.go @@ -22,7 +22,7 @@ var parseStyleTests = []struct { func TestValueParserStyleTag(t *testing.T) { for _, tt := range parseStyleTests { - actual := NewValueParser().Parse("cat", "", tt.customStyle) + actual := NewValueParser().Parse("cat", "", tt.customStyle, "", false) test.AssertResultWithContext(t, tt.expectedStyle, actual.Style, tt.customStyle) } } @@ -40,7 +40,7 @@ var parseValueTests = []struct { func TestValueParserParse(t *testing.T) { for _, tt := range parseValueTests { - actual := NewValueParser().Parse(tt.argument, tt.customTag, "") + actual := NewValueParser().Parse(tt.argument, tt.customTag, "", "", false) test.AssertResultWithContext(t, tt.argument, actual.Value, tt.testDescription) test.AssertResultWithContext(t, tt.expectedTag, actual.Tag, tt.testDescription) test.AssertResult(t, yaml.ScalarNode, actual.Kind) @@ -48,7 +48,18 @@ func TestValueParserParse(t *testing.T) { } func TestValueParserParseEmptyArray(t *testing.T) { - actual := NewValueParser().Parse("[]", "", "") + actual := NewValueParser().Parse("[]", "", "", "", false) test.AssertResult(t, "!!seq", actual.Tag) test.AssertResult(t, yaml.SequenceNode, actual.Kind) } + +func TestValueParserParseAlias(t *testing.T) { + actual := NewValueParser().Parse("bob", "", "", "", true) + test.AssertResult(t, "bob", actual.Value) + test.AssertResult(t, yaml.AliasNode, actual.Kind) +} + +func TestValueParserAnchorname(t *testing.T) { + actual := NewValueParser().Parse("caterpillar", "", "", "foo", false) + test.AssertResult(t, "foo", actual.Anchor) +}