diff --git a/pkg/yqlib/all_at_once_evaluator.go b/pkg/yqlib/all_at_once_evaluator.go index be6ccead..a8f087c5 100644 --- a/pkg/yqlib/all_at_once_evaluator.go +++ b/pkg/yqlib/all_at_once_evaluator.go @@ -68,6 +68,17 @@ func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string allDocuments.PushBackList(fileDocuments) fileIndex = fileIndex + 1 } + + if allDocuments.Len() == 0 { + candidateNode := &CandidateNode{ + Document: 0, + Filename: "", + Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode}, + FileIndex: 0, + } + allDocuments.PushBack(candidateNode) + } + matches, err := e.EvaluateCandidateNodes(expression, allDocuments) if err != nil { return err diff --git a/pkg/yqlib/operators_test.go b/pkg/yqlib/operators_test.go index 6c1e3f04..55083227 100644 --- a/pkg/yqlib/operators_test.go +++ b/pkg/yqlib/operators_test.go @@ -114,7 +114,7 @@ func formatYaml(yaml string, filename string) string { panic(err) } streamEvaluator := NewStreamEvaluator() - err = streamEvaluator.Evaluate(filename, strings.NewReader(yaml), node, printer) + _, err = streamEvaluator.Evaluate(filename, strings.NewReader(yaml), node, printer) if err != nil { panic(err) } diff --git a/pkg/yqlib/stream_evaluator.go b/pkg/yqlib/stream_evaluator.go index 17517720..f8e0efcd 100644 --- a/pkg/yqlib/stream_evaluator.go +++ b/pkg/yqlib/stream_evaluator.go @@ -12,7 +12,7 @@ import ( // Uses less memory than loading all documents and running the expression once, but this cannot process // cross document expressions. type StreamEvaluator interface { - Evaluate(filename string, reader io.Reader, node *ExpressionNode, printer Printer) error + Evaluate(filename string, reader io.Reader, node *ExpressionNode, printer Printer) (uint, error) EvaluateFiles(expression string, filenames []string, printer Printer) error EvaluateNew(expression string, printer Printer) error } @@ -49,7 +49,7 @@ func (s *streamEvaluator) EvaluateNew(expression string, printer Printer) error } func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer) error { - + var totalProcessDocs uint = 0 node, err := s.treeCreator.ParseExpression(expression) if err != nil { return err @@ -63,23 +63,28 @@ func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, p if err != nil { return err } - err = s.Evaluate(filename, reader, node, printer) + processedDocs, err := s.Evaluate(filename, reader, node, printer) if err != nil { return err } + totalProcessDocs = totalProcessDocs + processedDocs switch reader := reader.(type) { case *os.File: safelyCloseFile(reader) } } + + if totalProcessDocs == 0 { + return s.EvaluateNew(expression, printer) + } + return nil } -func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *ExpressionNode, printer Printer) error { +func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *ExpressionNode, printer Printer) (uint, error) { var currentIndex uint - decoder := yaml.NewDecoder(reader) for { var dataBucket yaml.Node @@ -87,9 +92,9 @@ func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *Expr if errorReading == io.EOF { s.fileIndex = s.fileIndex + 1 - return nil + return currentIndex, nil } else if errorReading != nil { - return errorReading + return currentIndex, errorReading } candidateNode := &CandidateNode{ Document: currentIndex, @@ -102,11 +107,11 @@ func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *Expr result, errorParsing := s.treeNavigator.GetMatchingNodes(Context{MatchingNodes: inputList}, node) if errorParsing != nil { - return errorParsing + return currentIndex, errorParsing } err := printer.PrintResults(result.MatchingNodes) if err != nil { - return err + return currentIndex, err } currentIndex = currentIndex + 1 } diff --git a/scripts/acceptance.sh b/scripts/acceptance.sh index 7564454b..ea0561ef 100755 --- a/scripts/acceptance.sh +++ b/scripts/acceptance.sh @@ -55,7 +55,7 @@ if [[ $? != 1 ]]; then exit 1 fi -# Test leading seperator logic +echo "Test: leading seperator logic" expected=$(cat examples/leading-seperator.yaml) X=$(cat examples/leading-seperator.yaml | ./yq e '.' -) @@ -113,7 +113,7 @@ if [[ $X != $expected ]]; then exit 1 fi -# handle empty files +echo "Test: handle empty files" ./yq e '.' examples/empty.yaml if [[ $? != 0 ]]; then echo "Expected no error when processing empty file but got one" @@ -126,6 +126,29 @@ if [[ $? != 0 ]]; then exit 1 fi +# run expression against empty file +touch temp.yaml +expected="apple: tree" + +./yq e '.apple = "tree"' temp.yaml -i +X=$(cat temp.yaml) +rm temp.yaml +if [[ $X != $expected ]]; then + echo "Write empty doc" + echo "Expected $expected but was $X" + exit 1 +fi + +touch temp.yaml + +./yq ea '.apple = "tree"' temp.yaml -i +X=$(cat temp.yaml) +rm temp.yaml +if [[ $X != $expected ]]; then + echo "Write all empty doc" + echo "Expected $expected but was $X" + exit 1 +fi echo "--success"