mirror of
https://github.com/mikefarah/yq.git
synced 2026-06-28 07:57:43 +00:00
When using --front-matter, yq creates a temporary file for the extracted YAML content but replaces the original filename in args with the temp file path. This caused the 'filename' operator to return the temp file path instead of the original filename. Added a filename alias mechanism: when front matter processing replaces the file path, it registers the original filename as an alias. The readDocuments and stream evaluator functions resolve aliases before setting candidateNode.filename. Fixes #2538 Co-authored-by: cobyfrombrooklyn-bot <cobyfrombrooklyn@gmail.com>
114 lines
3.0 KiB
Go
114 lines
3.0 KiB
Go
package yqlib
|
|
|
|
import (
|
|
"container/list"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
// A yaml expression evaluator that runs the expression multiple times for each given yaml document.
|
|
// 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, decoder Decoder) (uint, error)
|
|
EvaluateFiles(expression string, filenames []string, printer Printer, decoder Decoder) error
|
|
EvaluateNew(expression string, printer Printer) error
|
|
}
|
|
|
|
type streamEvaluator struct {
|
|
treeNavigator DataTreeNavigator
|
|
fileIndex int
|
|
}
|
|
|
|
func NewStreamEvaluator() StreamEvaluator {
|
|
return &streamEvaluator{treeNavigator: NewDataTreeNavigator()}
|
|
}
|
|
|
|
func (s *streamEvaluator) EvaluateNew(expression string, printer Printer) error {
|
|
node, err := ExpressionParser.ParseExpression(expression)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
candidateNode := createScalarNode(nil, "")
|
|
inputList := list.New()
|
|
inputList.PushBack(candidateNode)
|
|
|
|
result, errorParsing := s.treeNavigator.GetMatchingNodes(Context{MatchingNodes: inputList}, node)
|
|
if errorParsing != nil {
|
|
return errorParsing
|
|
}
|
|
return printer.PrintResults(result.MatchingNodes)
|
|
}
|
|
|
|
func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer, decoder Decoder) error {
|
|
var totalProcessDocs uint
|
|
node, err := ExpressionParser.ParseExpression(expression)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, filename := range filenames {
|
|
reader, err := readStream(filename)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
processedDocs, err := s.Evaluate(filename, reader, node, printer, decoder)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
totalProcessDocs = totalProcessDocs + processedDocs
|
|
|
|
switch reader := reader.(type) {
|
|
case *os.File:
|
|
safelyCloseFile(reader)
|
|
}
|
|
}
|
|
|
|
if totalProcessDocs == 0 {
|
|
// problem is I've already slurped the leading content sadface
|
|
return s.EvaluateNew(expression, printer)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *ExpressionNode, printer Printer, decoder Decoder) (uint, error) {
|
|
filename = resolveFilename(filename)
|
|
|
|
var currentIndex uint
|
|
err := decoder.Init(reader)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
for {
|
|
candidateNode, errorReading := decoder.Decode()
|
|
|
|
if errors.Is(errorReading, io.EOF) {
|
|
s.fileIndex = s.fileIndex + 1
|
|
return currentIndex, nil
|
|
} else if errorReading != nil {
|
|
return currentIndex, fmt.Errorf("bad file '%v': %w", filename, errorReading)
|
|
}
|
|
candidateNode.document = currentIndex
|
|
candidateNode.filename = filename
|
|
candidateNode.fileIndex = s.fileIndex
|
|
|
|
inputList := list.New()
|
|
inputList.PushBack(candidateNode)
|
|
|
|
result, errorParsing := s.treeNavigator.GetMatchingNodes(Context{MatchingNodes: inputList}, node)
|
|
if errorParsing != nil {
|
|
return currentIndex, errorParsing
|
|
}
|
|
err := printer.PrintResults(result.MatchingNodes)
|
|
|
|
if err != nil {
|
|
return currentIndex, err
|
|
}
|
|
currentIndex = currentIndex + 1
|
|
}
|
|
}
|