Fixed for most cases, except strip comments

This commit is contained in:
Mike Farah 2021-07-20 09:18:40 +10:00
parent 38dd4175fb
commit bbebebe30c
12 changed files with 199 additions and 18 deletions

View File

@ -40,4 +40,33 @@ testBasicExitStatus() {
assertEquals 1 "$?" assertEquals 1 "$?"
} }
testBasicExtractFieldWithSeperator() {
cat >test.yml <<EOL
---
name: chart-name
version: 1.2.3
EOL
X=$(./yq e '.name' test.yml)
assertEquals "chart-name" "$X"
}
testBasicExtractMultipleFieldWithSeperator() {
cat >test.yml <<EOL
---
name: chart-name
version: 1.2.3
---
name: thing
version: 1.2.3
EOL
read -r -d '' expected << EOM
chart-name
---
thing
EOM
X=$(./yq e '.name' test.yml)
assertEquals "$expected" "$X"
}
source ./scripts/shunit2 source ./scripts/shunit2

View File

@ -229,6 +229,116 @@ EOM
assertEquals "$expected" "$X" assertEquals "$expected" "$X"
} }
testLeadingSeperatorMultiDocEvalCommentsStripComments() {
cat >test.yml <<EOL
---
# hi peeps
# cool
a: test
---
# this is another doc
# great
b: sane
EOL
# it will be hard to remove that top level separator
read -r -d '' expected << EOM
a: test
---
b: sane
EOM
X=$(./yq e --header-preprocess=false '... comments=""' test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeperatorMultiDocEvalCommentsLeadingSepNoDocFlag() {
cat >test.yml <<EOL
---
# hi peeps
# cool
a: test
---
# this is another doc
# great
b: sane
EOL
# it will be hard to remove that top level separator
read -r -d '' expected << EOM
---
# hi peeps
# cool
a: test
# this is another doc
# great
b: sane
EOM
X=$(./yq e '.' --no-doc test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeperatorMultiDocEvalJsonFlag() {
cat >test.yml <<EOL
---
# hi peeps
# cool
a: test
EOL
cat >test2.yml <<EOL
---
# this is another doc
# great
b: sane
EOL
read -r -d '' expected << EOM
{
"a": "test"
}
{
"b": "sane"
}
EOM
X=$(./yq e '.' -j test.yml test2.yml)
assertEquals "$expected" "$X"
}
testLeadingSeperatorMultiDocEvalAllJsonFlag() {
cat >test.yml <<EOL
---
# hi peeps
# cool
a: test
EOL
cat >test2.yml <<EOL
---
# this is another doc
# great
b: sane
EOL
read -r -d '' expected << EOM
{
"a": "test"
}
{
"b": "sane"
}
EOM
X=$(./yq ea '.' -j test.yml test2.yml)
assertEquals "$expected" "$X"
}
testLeadingSeperatorMultiDocEvalAll() { testLeadingSeperatorMultiDocEvalAll() {
read -r -d '' expected << EOM read -r -d '' expected << EOM
--- ---

View File

@ -1,5 +1,6 @@
package cmd package cmd
var leadingContentPreProcessing = true
var unwrapScalar = true var unwrapScalar = true
var writeInplace = false var writeInplace = false

View File

@ -112,7 +112,7 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
switch len(args) { switch len(args) {
case 0: case 0:
if pipingStdIn { if pipingStdIn {
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer) err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing)
} else { } else {
cmd.Println(cmd.UsageString()) cmd.Println(cmd.UsageString())
return nil return nil
@ -121,10 +121,10 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
if nullInput { if nullInput {
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(args[0]), printer, "") err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(args[0]), printer, "")
} else { } else {
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer) err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer, leadingContentPreProcessing)
} }
default: default:
err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer) err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing)
} }
completedSuccessfully = err == nil completedSuccessfully = err == nil

View File

@ -125,7 +125,7 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
switch len(args) { switch len(args) {
case 0: case 0:
if pipingStdIn { if pipingStdIn {
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer) err = streamEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing)
} else { } else {
cmd.Println(cmd.UsageString()) cmd.Println(cmd.UsageString())
return nil return nil
@ -134,10 +134,10 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
if nullInput { if nullInput {
err = streamEvaluator.EvaluateNew(processExpression(args[0]), printer, "") err = streamEvaluator.EvaluateNew(processExpression(args[0]), printer, "")
} else { } else {
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer) err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer, leadingContentPreProcessing)
} }
default: default:
err = streamEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer) err = streamEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing)
} }
completedSuccessfully = err == nil completedSuccessfully = err == nil

View File

@ -55,6 +55,7 @@ See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.`,
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors") rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors") rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")
rootCmd.PersistentFlags().StringVarP(&frontMatter, "front-matter", "f", "", "(extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact") rootCmd.PersistentFlags().StringVarP(&frontMatter, "front-matter", "f", "", "(extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact")
rootCmd.PersistentFlags().BoolVarP(&leadingContentPreProcessing, "header-preprocess", "", true, "Slurp any header comments and seperators before processing expression. This is a workaround for go-yaml to persist header content. You will want this off if you want to remove leading comments.")
rootCmd.AddCommand( rootCmd.AddCommand(
createEvaluateSequenceCommand(), createEvaluateSequenceCommand(),
createEvaluateAllCommand(), createEvaluateAllCommand(),

View File

@ -1,2 +1,8 @@
--- ---
{"a":{"b":1}} # hi peeps
# cool
a: test
---
# this is another doc
# great
b: sane

View File

@ -8,7 +8,7 @@ import (
// A yaml expression evaluator that runs the expression once against all files/nodes in memory. // A yaml expression evaluator that runs the expression once against all files/nodes in memory.
type Evaluator interface { type Evaluator interface {
EvaluateFiles(expression string, filenames []string, printer Printer) error EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool) error
// EvaluateNodes takes an expression and one or more yaml nodes, returning a list of matching candidate nodes // EvaluateNodes takes an expression and one or more yaml nodes, returning a list of matching candidate nodes
EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error)
@ -46,13 +46,13 @@ func (e *allAtOnceEvaluator) EvaluateCandidateNodes(expression string, inputCand
return context.MatchingNodes, nil return context.MatchingNodes, nil
} }
func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer) error { func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool) error {
fileIndex := 0 fileIndex := 0
firstFileLeadingContent := "" firstFileLeadingContent := ""
var allDocuments *list.List = list.New() var allDocuments *list.List = list.New()
for _, filename := range filenames { for _, filename := range filenames {
reader, leadingContent, err := readStream(filename) reader, leadingContent, err := readStream(filename, leadingContentPreProcessing)
if err != nil { if err != nil {
return err return err
} }

View File

@ -128,10 +128,15 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List, leadingContent s
} }
if !printedLead { if !printedLead {
// dont print leading comments and seperator if:
// - we are print json; or
// - we are printing an unwrapped scalar node
if !p.outputToJSON && (mappedDoc.Node.Kind != yaml.ScalarNode || !p.unwrapScalar) {
// we want to print this after the seperator logic // we want to print this after the seperator logic
if err := p.writeString(bufferedWriter, leadingContent); err != nil { if err := p.writeString(bufferedWriter, leadingContent); err != nil {
return err return err
} }
}
printedLead = true printedLead = true
} }

View File

@ -276,6 +276,31 @@ a: coconut
test.AssertResult(t, expected, output.String()) test.AssertResult(t, expected, output.String())
} }
func TestPrinterScalarWithLeadingCont(t *testing.T) {
var output bytes.Buffer
var writer = bufio.NewWriter(&output)
printer := NewPrinter(writer, false, true, false, 2, true)
node, err := NewExpressionParser().ParseExpression(".a")
if err != nil {
panic(err)
}
streamEvaluator := NewStreamEvaluator()
_, err = streamEvaluator.Evaluate("sample", strings.NewReader(multiDocSample), node, printer, "# blah\n")
if err != nil {
panic(err)
}
writer.Flush()
expected := `banana
---
apple
---
coconut
`
test.AssertResult(t, expected, output.String())
}
func TestPrinterMultipleDocsJson(t *testing.T) { func TestPrinterMultipleDocsJson(t *testing.T) {
var output bytes.Buffer var output bytes.Buffer
var writer = bufio.NewWriter(&output) var writer = bufio.NewWriter(&output)
@ -288,7 +313,7 @@ func TestPrinterMultipleDocsJson(t *testing.T) {
panic(err) panic(err)
} }
err = printer.PrintResults(inputs, "") err = printer.PrintResults(inputs, "# ignore this")
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -13,7 +13,7 @@ import (
// cross document expressions. // cross document expressions.
type StreamEvaluator interface { type StreamEvaluator interface {
Evaluate(filename string, reader io.Reader, node *ExpressionNode, printer Printer, leadingContent string) (uint, error) Evaluate(filename string, reader io.Reader, node *ExpressionNode, printer Printer, leadingContent string) (uint, error)
EvaluateFiles(expression string, filenames []string, printer Printer) error EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool) error
EvaluateNew(expression string, printer Printer, leadingContent string) error EvaluateNew(expression string, printer Printer, leadingContent string) error
} }
@ -48,7 +48,7 @@ func (s *streamEvaluator) EvaluateNew(expression string, printer Printer, leadin
return printer.PrintResults(result.MatchingNodes, leadingContent) return printer.PrintResults(result.MatchingNodes, leadingContent)
} }
func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer) error { func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool) error {
var totalProcessDocs uint = 0 var totalProcessDocs uint = 0
node, err := s.treeCreator.ParseExpression(expression) node, err := s.treeCreator.ParseExpression(expression)
if err != nil { if err != nil {
@ -58,7 +58,7 @@ func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, p
var firstFileLeadingContent string var firstFileLeadingContent string
for index, filename := range filenames { for index, filename := range filenames {
reader, leadingContent, err := readStream(filename) reader, leadingContent, err := readStream(filename, leadingContentPreProcessing)
if index == 0 { if index == 0 {
firstFileLeadingContent = leadingContent firstFileLeadingContent = leadingContent

View File

@ -11,7 +11,7 @@ import (
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
) )
func readStream(filename string) (io.Reader, string, error) { func readStream(filename string, leadingContentPreProcessing bool) (io.Reader, string, error) {
var commentLineRegEx = regexp.MustCompile(`^\s*#`) var commentLineRegEx = regexp.MustCompile(`^\s*#`)
var reader *bufio.Reader var reader *bufio.Reader
if filename == "-" { if filename == "-" {
@ -27,6 +27,10 @@ func readStream(filename string) (io.Reader, string, error) {
} }
var sb strings.Builder var sb strings.Builder
if !leadingContentPreProcessing {
return reader, "", nil
}
for { for {
peekBytes, err := reader.Peek(3) peekBytes, err := reader.Peek(3)