mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
refactored
This commit is contained in:
@@ -11,19 +11,18 @@ var unwrapScalar = true
|
||||
var customStyle = ""
|
||||
var anchorName = ""
|
||||
var makeAlias = false
|
||||
var stripComments = false
|
||||
var writeInplace = false
|
||||
var writeScript = ""
|
||||
var sourceYamlFile = ""
|
||||
var outputToJSON = false
|
||||
var exitStatus = false
|
||||
var prettyPrint = false
|
||||
var explodeAnchors = false
|
||||
var forceColor = false
|
||||
var forceNoColor = false
|
||||
var colorsEnabled = false
|
||||
var defaultValue = ""
|
||||
var indent = 2
|
||||
var printDocSeparators = true
|
||||
var overwriteFlag = false
|
||||
var autoCreateFlag = true
|
||||
var arrayMergeStrategyFlag = "update"
|
||||
|
||||
26
cmd/root.go
26
cmd/root.go
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib/treeops"
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
||||
"github.com/spf13/cobra"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
@@ -40,7 +40,7 @@ func New() *cobra.Command {
|
||||
// }
|
||||
cmd.SilenceUsage = true
|
||||
|
||||
var treeCreator = treeops.NewPathTreeCreator()
|
||||
var treeCreator = yqlib.NewPathTreeCreator()
|
||||
|
||||
expression := ""
|
||||
if len(args) > 0 {
|
||||
@@ -53,13 +53,13 @@ func New() *cobra.Command {
|
||||
}
|
||||
|
||||
if outputToJSON {
|
||||
explodeOp := treeops.Operation{OperationType: treeops.Explode}
|
||||
explodeNode := treeops.PathTreeNode{Operation: &explodeOp}
|
||||
pipeOp := treeops.Operation{OperationType: treeops.Pipe}
|
||||
pathNode = &treeops.PathTreeNode{Operation: &pipeOp, Lhs: pathNode, Rhs: &explodeNode}
|
||||
explodeOp := yqlib.Operation{OperationType: yqlib.Explode}
|
||||
explodeNode := yqlib.PathTreeNode{Operation: &explodeOp}
|
||||
pipeOp := yqlib.Operation{OperationType: yqlib.Pipe}
|
||||
pathNode = &yqlib.PathTreeNode{Operation: &pipeOp, Lhs: pathNode, Rhs: &explodeNode}
|
||||
}
|
||||
|
||||
matchingNodes, err := evaluate("-", pathNode)
|
||||
matchingNodes, err := yqlib.Evaluate("-", pathNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -71,7 +71,14 @@ func New() *cobra.Command {
|
||||
|
||||
out := cmd.OutOrStdout()
|
||||
|
||||
return printResults(matchingNodes, out)
|
||||
fileInfo, _ := os.Stdout.Stat()
|
||||
|
||||
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
|
||||
colorsEnabled = true
|
||||
}
|
||||
printer := yqlib.NewPrinter(outputToJSON, unwrapScalar, colorsEnabled, indent, printDocSeparators)
|
||||
|
||||
return printer.PrintResults(matchingNodes, out)
|
||||
},
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
@@ -92,8 +99,7 @@ func New() *cobra.Command {
|
||||
}
|
||||
|
||||
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose mode")
|
||||
rootCmd.PersistentFlags().BoolVarP(&outputToJSON, "tojson", "j", false, "output as json. By default it prints a json document in one line, use the prettyPrint flag to print a formatted doc.")
|
||||
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print")
|
||||
rootCmd.PersistentFlags().BoolVarP(&outputToJSON, "tojson", "j", false, "output as json. Set indent to 0 to print json in one line.")
|
||||
rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output")
|
||||
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
|
||||
|
||||
|
||||
232
cmd/utils.go
232
cmd/utils.go
@@ -1,232 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"container/list"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib/treeops"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func readStream(filename string) (*yaml.Decoder, error) {
|
||||
if filename == "" {
|
||||
return nil, errors.New("Must provide filename")
|
||||
}
|
||||
|
||||
var stream io.Reader
|
||||
if filename == "-" {
|
||||
stream = bufio.NewReader(os.Stdin)
|
||||
} else {
|
||||
file, err := os.Open(filename) // nolint gosec
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer safelyCloseFile(file)
|
||||
stream = file
|
||||
}
|
||||
return yaml.NewDecoder(stream), nil
|
||||
}
|
||||
|
||||
func evaluate(filename string, node *treeops.PathTreeNode) (*list.List, error) {
|
||||
|
||||
var treeNavigator = treeops.NewDataTreeNavigator(treeops.NavigationPrefs{})
|
||||
|
||||
var matchingNodes = list.New()
|
||||
|
||||
var currentIndex uint = 0
|
||||
var decoder, err = readStream(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
var dataBucket yaml.Node
|
||||
errorReading := decoder.Decode(&dataBucket)
|
||||
|
||||
if errorReading == io.EOF {
|
||||
return matchingNodes, nil
|
||||
} else if errorReading != nil {
|
||||
return nil, errorReading
|
||||
}
|
||||
candidateNode := &treeops.CandidateNode{
|
||||
Document: currentIndex,
|
||||
Filename: filename,
|
||||
Node: &dataBucket,
|
||||
}
|
||||
inputList := list.New()
|
||||
inputList.PushBack(candidateNode)
|
||||
|
||||
newMatches, errorParsing := treeNavigator.GetMatchingNodes(inputList, node)
|
||||
if errorParsing != nil {
|
||||
return nil, errorParsing
|
||||
}
|
||||
matchingNodes.PushBackList(newMatches)
|
||||
currentIndex = currentIndex + 1
|
||||
}
|
||||
|
||||
return matchingNodes, nil
|
||||
}
|
||||
|
||||
func printNode(node *yaml.Node, writer io.Writer) error {
|
||||
var encoder yqlib.Encoder
|
||||
if node.Kind == yaml.ScalarNode && unwrapScalar && !outputToJSON {
|
||||
return writeString(writer, node.Value+"\n")
|
||||
}
|
||||
if outputToJSON {
|
||||
encoder = yqlib.NewJsonEncoder(writer, prettyPrint, indent)
|
||||
} else {
|
||||
encoder = yqlib.NewYamlEncoder(writer, indent, colorsEnabled)
|
||||
}
|
||||
return encoder.Encode(node)
|
||||
}
|
||||
|
||||
func removeComments(matchingNodes *list.List) {
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*treeops.CandidateNode)
|
||||
removeCommentOfNode(candidate.Node)
|
||||
}
|
||||
}
|
||||
|
||||
func removeCommentOfNode(node *yaml.Node) {
|
||||
node.HeadComment = ""
|
||||
node.LineComment = ""
|
||||
node.FootComment = ""
|
||||
|
||||
for _, child := range node.Content {
|
||||
removeCommentOfNode(child)
|
||||
}
|
||||
}
|
||||
|
||||
func setStyle(matchingNodes *list.List, style yaml.Style) {
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*treeops.CandidateNode)
|
||||
updateStyleOfNode(candidate.Node, style)
|
||||
}
|
||||
}
|
||||
|
||||
func updateStyleOfNode(node *yaml.Node, style yaml.Style) {
|
||||
node.Style = style
|
||||
|
||||
for _, child := range node.Content {
|
||||
updateStyleOfNode(child, style)
|
||||
}
|
||||
}
|
||||
|
||||
func writeString(writer io.Writer, txt string) error {
|
||||
_, errorWriting := writer.Write([]byte(txt))
|
||||
return errorWriting
|
||||
}
|
||||
|
||||
func printResults(matchingNodes *list.List, writer io.Writer) error {
|
||||
if prettyPrint {
|
||||
setStyle(matchingNodes, 0)
|
||||
}
|
||||
|
||||
if stripComments {
|
||||
removeComments(matchingNodes)
|
||||
}
|
||||
|
||||
fileInfo, _ := os.Stdout.Stat()
|
||||
|
||||
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
|
||||
colorsEnabled = true
|
||||
}
|
||||
|
||||
bufferedWriter := bufio.NewWriter(writer)
|
||||
defer safelyFlush(bufferedWriter)
|
||||
|
||||
if matchingNodes.Len() == 0 {
|
||||
log.Debug("no matching results, nothing to print")
|
||||
if defaultValue != "" {
|
||||
return writeString(bufferedWriter, defaultValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var errorWriting error
|
||||
|
||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||
mappedDoc := el.Value.(*treeops.CandidateNode)
|
||||
|
||||
switch printMode {
|
||||
case "p":
|
||||
errorWriting = writeString(bufferedWriter, mappedDoc.PathStackToString()+"\n")
|
||||
if errorWriting != nil {
|
||||
return errorWriting
|
||||
}
|
||||
case "pv", "vp":
|
||||
// put it into a node and print that.
|
||||
var parentNode = yaml.Node{Kind: yaml.MappingNode}
|
||||
parentNode.Content = make([]*yaml.Node, 2)
|
||||
parentNode.Content[0] = &yaml.Node{Kind: yaml.ScalarNode, Value: mappedDoc.PathStackToString()}
|
||||
if mappedDoc.Node.Kind == yaml.DocumentNode {
|
||||
parentNode.Content[1] = mappedDoc.Node.Content[0]
|
||||
} else {
|
||||
parentNode.Content[1] = mappedDoc.Node
|
||||
}
|
||||
if err := printNode(&parentNode, bufferedWriter); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := printNode(mappedDoc.Node, bufferedWriter); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func safelyRenameFile(from string, to string) {
|
||||
if renameError := os.Rename(from, to); renameError != nil {
|
||||
log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to)
|
||||
log.Debug(renameError.Error())
|
||||
// can't do this rename when running in docker to a file targeted in a mounted volume,
|
||||
// so gracefully degrade to copying the entire contents.
|
||||
if copyError := copyFileContents(from, to); copyError != nil {
|
||||
log.Errorf("Failed copying from %v to %v", from, to)
|
||||
log.Error(copyError.Error())
|
||||
} else {
|
||||
removeErr := os.Remove(from)
|
||||
if removeErr != nil {
|
||||
log.Errorf("failed removing original file: %s", from)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thanks https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
|
||||
func copyFileContents(src, dst string) (err error) {
|
||||
in, err := os.Open(src) // nolint gosec
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer safelyCloseFile(in)
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer safelyCloseFile(out)
|
||||
if _, err = io.Copy(out, in); err != nil {
|
||||
return err
|
||||
}
|
||||
return out.Sync()
|
||||
}
|
||||
|
||||
func safelyFlush(writer *bufio.Writer) {
|
||||
if err := writer.Flush(); err != nil {
|
||||
log.Error("Error flushing writer!")
|
||||
log.Error(err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
func safelyCloseFile(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
log.Error("Error closing file!")
|
||||
log.Error(err.Error())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user