diff --git a/examples/empty.yaml b/examples/empty.yaml index e69de29..308ec1d 100644 --- a/examples/empty.yaml +++ b/examples/empty.yaml @@ -0,0 +1 @@ +# comment diff --git a/pkg/yqlib/all_at_once_evaluator.go b/pkg/yqlib/all_at_once_evaluator.go index a8f087c..41041c0 100644 --- a/pkg/yqlib/all_at_once_evaluator.go +++ b/pkg/yqlib/all_at_once_evaluator.go @@ -2,6 +2,7 @@ package yqlib import ( "container/list" + "os" yaml "gopkg.in/yaml.v3" ) @@ -77,6 +78,18 @@ func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string FileIndex: 0, } allDocuments.PushBack(candidateNode) + + if len(filenames) > 0 { + reader, _, err := readStream(filenames[0]) + if err != nil { + return err + } + switch reader := reader.(type) { + case *os.File: + defer safelyCloseFile(reader) + } + printer.SetPreamble(reader) + } } matches, err := e.EvaluateCandidateNodes(expression, allDocuments) diff --git a/pkg/yqlib/printer.go b/pkg/yqlib/printer.go index fc0d549..9521da5 100644 --- a/pkg/yqlib/printer.go +++ b/pkg/yqlib/printer.go @@ -12,6 +12,9 @@ type Printer interface { PrintResults(matchingNodes *list.List) error PrintedAnything() bool SetPrintLeadingSeperator(bool) + + // preamble yaml content + SetPreamble(reader io.Reader) } type resultsPrinter struct { @@ -26,6 +29,7 @@ type resultsPrinter struct { previousFileIndex int printedMatches bool treeNavigator DataTreeNavigator + preambleReader io.Reader } func NewPrinter(writer io.Writer, outputToJSON bool, unwrapScalar bool, colorsEnabled bool, indent int, printDocSeparators bool) Printer { @@ -48,6 +52,10 @@ func (p *resultsPrinter) SetPrintLeadingSeperator(printLeadingSeperator bool) { } } +func (p *resultsPrinter) SetPreamble(reader io.Reader) { + p.preambleReader = reader +} + func (p *resultsPrinter) PrintedAnything() bool { return p.printedMatches } @@ -95,6 +103,14 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error { bufferedWriter := bufio.NewWriter(p.writer) defer p.safelyFlush(bufferedWriter) + if p.preambleReader != nil && !p.outputToJSON { + log.Debug("Piping preamble reader...") + _, err := io.Copy(bufferedWriter, p.preambleReader) + if err != nil { + return err + } + } + if matchingNodes.Len() == 0 { log.Debug("no matching results, nothing to print") return nil diff --git a/pkg/yqlib/stream_evaluator.go b/pkg/yqlib/stream_evaluator.go index f8e0efc..9c0521d 100644 --- a/pkg/yqlib/stream_evaluator.go +++ b/pkg/yqlib/stream_evaluator.go @@ -76,6 +76,19 @@ func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, p } if totalProcessDocs == 0 { + + if len(filenames) > 0 { + reader, _, err := readStream(filenames[0]) + if err != nil { + return err + } + switch reader := reader.(type) { + case *os.File: + defer safelyCloseFile(reader) + } + printer.SetPreamble(reader) + } + return s.EvaluateNew(expression, printer) } diff --git a/scripts/acceptance.sh b/scripts/acceptance.sh index ea0561e..2ea7902 100755 --- a/scripts/acceptance.sh +++ b/scripts/acceptance.sh @@ -150,6 +150,33 @@ if [[ $X != $expected ]]; then exit 1 fi +echo "Test: handle empty files with just comments" +echo "# comment" > temp.yaml +read -r -d '' expected << EOM +# comment +apple: tree +EOM + +./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 + +echo "# comment" > 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" set -e