mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 05:38:04 +00:00
Extracted out evaluators
This commit is contained in:
parent
e451119014
commit
fc3af441e5
@ -40,23 +40,23 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
|
|||||||
colorsEnabled = true
|
colorsEnabled = true
|
||||||
}
|
}
|
||||||
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
||||||
|
allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator()
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = yqlib.EvaluateAllFileStreams("", []string{"-"}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles("", []string{"-"}, printer)
|
||||||
} else {
|
} else {
|
||||||
cmd.Println(cmd.UsageString())
|
cmd.Println(cmd.UsageString())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if nullInput {
|
if nullInput {
|
||||||
err = yqlib.EvaluateAllFileStreams(args[0], []string{}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles(args[0], []string{}, printer)
|
||||||
} else {
|
} else {
|
||||||
err = yqlib.EvaluateAllFileStreams("", []string{args[0]}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles("", []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = yqlib.EvaluateAllFileStreams(args[0], args[1:], printer)
|
err = allAtOnceEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.SilenceUsage = true
|
cmd.SilenceUsage = true
|
||||||
|
@ -41,22 +41,25 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
||||||
|
|
||||||
|
streamEvaluator := yqlib.NewStreamEvaluator()
|
||||||
|
allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator()
|
||||||
|
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = yqlib.EvaluateFileStreamsSequence("", []string{"-"}, printer)
|
err = streamEvaluator.EvaluateFiles("", []string{"-"}, printer)
|
||||||
} else {
|
} else {
|
||||||
cmd.Println(cmd.UsageString())
|
cmd.Println(cmd.UsageString())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if nullInput {
|
if nullInput {
|
||||||
err = yqlib.EvaluateAllFileStreams(args[0], []string{}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles(args[0], []string{}, printer)
|
||||||
} else {
|
} else {
|
||||||
err = yqlib.EvaluateFileStreamsSequence("", []string{args[0]}, printer)
|
err = streamEvaluator.EvaluateFiles("", []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = yqlib.EvaluateFileStreamsSequence(args[0], args[1:], printer)
|
err = streamEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.SilenceUsage = true
|
cmd.SilenceUsage = true
|
||||||
|
45
pkg/yqlib/all_at_once_evaluator.go
Normal file
45
pkg/yqlib/all_at_once_evaluator.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "container/list"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Loads all yaml documents of all files given into memory, then runs the given expression once.
|
||||||
|
**/
|
||||||
|
type Evaluator interface {
|
||||||
|
EvaluateFiles(expression string, filenames []string, printer Printer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type allAtOnceEvaluator struct {
|
||||||
|
treeNavigator DataTreeNavigator
|
||||||
|
treeCreator PathTreeCreator
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAllAtOnceEvaluator() Evaluator {
|
||||||
|
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator(), treeCreator: NewPathTreeCreator()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer) error {
|
||||||
|
fileIndex := 0
|
||||||
|
node, err := treeCreator.ParsePath(expression)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var allDocuments *list.List = list.New()
|
||||||
|
for _, filename := range filenames {
|
||||||
|
reader, err := readStream(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fileDocuments, err := readDocuments(reader, filename, fileIndex)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
allDocuments.PushBackList(fileDocuments)
|
||||||
|
fileIndex = fileIndex + 1
|
||||||
|
}
|
||||||
|
matches, err := treeNavigator.GetMatchingNodes(allDocuments, node)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return printer.PrintResults(matches)
|
||||||
|
}
|
@ -5,17 +5,9 @@ import (
|
|||||||
|
|
||||||
"container/list"
|
"container/list"
|
||||||
|
|
||||||
"gopkg.in/op/go-logging.v1"
|
logging "gopkg.in/op/go-logging.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dataTreeNavigator struct {
|
|
||||||
navigationPrefs NavigationPrefs
|
|
||||||
}
|
|
||||||
|
|
||||||
type NavigationPrefs struct {
|
|
||||||
FollowAlias bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type DataTreeNavigator interface {
|
type DataTreeNavigator interface {
|
||||||
// given a list of CandidateEntities and a pathNode,
|
// given a list of CandidateEntities and a pathNode,
|
||||||
// this will process the list against the given pathNode and return
|
// this will process the list against the given pathNode and return
|
||||||
@ -23,8 +15,11 @@ type DataTreeNavigator interface {
|
|||||||
GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error)
|
GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDataTreeNavigator(navigationPrefs NavigationPrefs) DataTreeNavigator {
|
type dataTreeNavigator struct {
|
||||||
return &dataTreeNavigator{navigationPrefs}
|
}
|
||||||
|
|
||||||
|
func NewDataTreeNavigator() DataTreeNavigator {
|
||||||
|
return &dataTreeNavigator{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
@ -29,6 +29,6 @@ yq eval 'fileIndex' sample.yml
|
|||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
73
|
0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -90,7 +90,8 @@ func formatYaml(yaml string) string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
err = EvaluateStream("sample.yaml", strings.NewReader(yaml), node, printer)
|
streamEvaluator := NewStreamEvaluator()
|
||||||
|
err = streamEvaluator.Evaluate("sample.yaml", strings.NewReader(yaml), node, printer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -161,12 +162,14 @@ func documentScenarios(t *testing.T, title string, scenarios []expressionScenari
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
err = EvaluateStream("sample.yaml", strings.NewReader(formattedDoc), node, printer)
|
streamEvaluator := NewStreamEvaluator()
|
||||||
|
err = streamEvaluator.Evaluate("sample.yaml", strings.NewReader(formattedDoc), node, printer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = EvaluateAllFileStreams(s.expression, []string{}, printer)
|
allAtOnceEvaluator := NewAllAtOnceEvaluator()
|
||||||
|
err = allAtOnceEvaluator.EvaluateFiles(s.expression, []string{}, printer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
85
pkg/yqlib/stream_evaluator.go
Normal file
85
pkg/yqlib/stream_evaluator.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StreamEvaluator interface {
|
||||||
|
Evaluate(filename string, reader io.Reader, node *PathTreeNode, printer Printer) error
|
||||||
|
EvaluateFiles(expression string, filenames []string, printer Printer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type streamEvaluator struct {
|
||||||
|
treeNavigator DataTreeNavigator
|
||||||
|
treeCreator PathTreeCreator
|
||||||
|
fileIndex int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStreamEvaluator() StreamEvaluator {
|
||||||
|
return &streamEvaluator{treeNavigator: NewDataTreeNavigator(), treeCreator: NewPathTreeCreator()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *streamEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer) error {
|
||||||
|
|
||||||
|
node, err := treeCreator.ParsePath(expression)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
reader, err := readStream(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = s.Evaluate(filename, reader, node, printer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch reader := reader.(type) {
|
||||||
|
case *os.File:
|
||||||
|
safelyCloseFile(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *PathTreeNode, printer Printer) error {
|
||||||
|
|
||||||
|
var currentIndex uint
|
||||||
|
|
||||||
|
decoder := yaml.NewDecoder(reader)
|
||||||
|
for {
|
||||||
|
var dataBucket yaml.Node
|
||||||
|
errorReading := decoder.Decode(&dataBucket)
|
||||||
|
|
||||||
|
if errorReading == io.EOF {
|
||||||
|
s.fileIndex = s.fileIndex + 1
|
||||||
|
return nil
|
||||||
|
} else if errorReading != nil {
|
||||||
|
return errorReading
|
||||||
|
}
|
||||||
|
candidateNode := &CandidateNode{
|
||||||
|
Document: currentIndex,
|
||||||
|
Filename: filename,
|
||||||
|
Node: &dataBucket,
|
||||||
|
FileIndex: s.fileIndex,
|
||||||
|
}
|
||||||
|
inputList := list.New()
|
||||||
|
inputList.PushBack(candidateNode)
|
||||||
|
|
||||||
|
matches, errorParsing := treeNavigator.GetMatchingNodes(inputList, node)
|
||||||
|
if errorParsing != nil {
|
||||||
|
return errorParsing
|
||||||
|
}
|
||||||
|
err := printer.PrintResults(matches)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
currentIndex = currentIndex + 1
|
||||||
|
}
|
||||||
|
}
|
@ -11,11 +11,9 @@ import (
|
|||||||
|
|
||||||
//TODO: convert to interface + struct
|
//TODO: convert to interface + struct
|
||||||
|
|
||||||
var treeNavigator = NewDataTreeNavigator(NavigationPrefs{})
|
var treeNavigator = NewDataTreeNavigator()
|
||||||
var treeCreator = NewPathTreeCreator()
|
var treeCreator = NewPathTreeCreator()
|
||||||
|
|
||||||
var fileIndex = 0
|
|
||||||
|
|
||||||
func readStream(filename string) (io.Reader, error) {
|
func readStream(filename string) (io.Reader, error) {
|
||||||
if filename == "-" {
|
if filename == "-" {
|
||||||
return bufio.NewReader(os.Stdin), nil
|
return bufio.NewReader(os.Stdin), nil
|
||||||
@ -24,42 +22,6 @@ func readStream(filename string) (io.Reader, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func EvaluateStream(filename string, reader io.Reader, node *PathTreeNode, printer Printer) error {
|
|
||||||
|
|
||||||
var currentIndex uint = 0
|
|
||||||
|
|
||||||
decoder := yaml.NewDecoder(reader)
|
|
||||||
for {
|
|
||||||
var dataBucket yaml.Node
|
|
||||||
errorReading := decoder.Decode(&dataBucket)
|
|
||||||
|
|
||||||
if errorReading == io.EOF {
|
|
||||||
fileIndex = fileIndex + 1
|
|
||||||
return nil
|
|
||||||
} else if errorReading != nil {
|
|
||||||
return errorReading
|
|
||||||
}
|
|
||||||
candidateNode := &CandidateNode{
|
|
||||||
Document: currentIndex,
|
|
||||||
Filename: filename,
|
|
||||||
Node: &dataBucket,
|
|
||||||
FileIndex: fileIndex,
|
|
||||||
}
|
|
||||||
inputList := list.New()
|
|
||||||
inputList.PushBack(candidateNode)
|
|
||||||
|
|
||||||
matches, errorParsing := treeNavigator.GetMatchingNodes(inputList, node)
|
|
||||||
if errorParsing != nil {
|
|
||||||
return errorParsing
|
|
||||||
}
|
|
||||||
err := printer.PrintResults(matches)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
currentIndex = currentIndex + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readDocuments(reader io.Reader, filename string, fileIndex int) (*list.List, error) {
|
func readDocuments(reader io.Reader, filename string, fileIndex int) (*list.List, error) {
|
||||||
decoder := yaml.NewDecoder(reader)
|
decoder := yaml.NewDecoder(reader)
|
||||||
inputList := list.New()
|
inputList := list.New()
|
||||||
@ -91,57 +53,6 @@ func readDocuments(reader io.Reader, filename string, fileIndex int) (*list.List
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func EvaluateAllFileStreams(expression string, filenames []string, printer Printer) error {
|
|
||||||
fileIndex := 0
|
|
||||||
node, err := treeCreator.ParsePath(expression)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var allDocuments *list.List = list.New()
|
|
||||||
for _, filename := range filenames {
|
|
||||||
reader, err := readStream(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fileDocuments, err := readDocuments(reader, filename, fileIndex)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
allDocuments.PushBackList(fileDocuments)
|
|
||||||
fileIndex = fileIndex + 1
|
|
||||||
}
|
|
||||||
matches, err := treeNavigator.GetMatchingNodes(allDocuments, node)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return printer.PrintResults(matches)
|
|
||||||
}
|
|
||||||
|
|
||||||
func EvaluateFileStreamsSequence(expression string, filenames []string, printer Printer) error {
|
|
||||||
|
|
||||||
node, err := treeCreator.ParsePath(expression)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, filename := range filenames {
|
|
||||||
reader, err := readStream(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = EvaluateStream(filename, reader, node, printer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch reader := reader.(type) {
|
|
||||||
case *os.File:
|
|
||||||
safelyCloseFile(reader)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// func safelyRenameFile(from string, to string) {
|
// func safelyRenameFile(from string, to string) {
|
||||||
// if renameError := os.Rename(from, to); renameError != nil {
|
// if renameError := os.Rename(from, to); renameError != nil {
|
||||||
// log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to)
|
// log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to)
|
||||||
|
Loading…
Reference in New Issue
Block a user