mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Refactoring
This commit is contained in:
parent
a3cebec2fd
commit
d7392f7b58
@ -94,6 +94,24 @@ func TestReadCmd(t *testing.T) {
|
||||
test.AssertResult(t, "2\n", result.Output)
|
||||
}
|
||||
|
||||
// func TestReadRawCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "read examples/sample.yaml b.c")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// test.AssertResult(t, "21\n", result.Output)
|
||||
// }
|
||||
|
||||
// func TestReadRawMultiCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "read examples/sample.yaml b.c")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// test.AssertResult(t, "21\n", result.Output)
|
||||
// }
|
||||
|
||||
func TestReadInvalidDocumentIndexCmd(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "read -df examples/sample.yaml b.c")
|
||||
|
6
go.mod
6
go.mod
@ -1,11 +1,11 @@
|
||||
module github.com/mikefarah/yq/v3
|
||||
|
||||
require (
|
||||
github.com/mikefarah/yaml/v2 v2.4.0
|
||||
github.com/mikefarah/yaml/v2 v2.4.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/spf13/cobra v0.0.5
|
||||
golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0 // indirect
|
||||
gopkg.in/imdario/mergo.v0 v0.3.7
|
||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 // indirect
|
||||
gopkg.in/imdario/mergo.v0 v0.3.7 // indirect
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2
|
||||
)
|
||||
|
7
go.sum
7
go.sum
@ -35,14 +35,21 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0 h1:s5lp4ug7qHzUccgyFdjsX7OZDzHXRaePrF3B3vmUiuM=
|
||||
golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 h1:kJQZhwFzSwJS2BxboKjdZzWczQOZx8VuH7Y8hhuGUtM=
|
||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/imdario/mergo.v0 v0.3.7 h1:QDotlIZtaO/p+Um0ok18HRTpq5i5/SAk/qprsor+9c8=
|
||||
|
@ -2,34 +2,50 @@ package yqlib
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type ValueParser interface {
|
||||
ParseValue(argument string) interface{}
|
||||
Parse(argument string, customTag string) *yaml.Node
|
||||
}
|
||||
|
||||
type valueParser struct{}
|
||||
|
||||
func NewValueParser() ValueParser {
|
||||
return &valueParser{}
|
||||
type valueParser struct {
|
||||
log *logging.Logger
|
||||
}
|
||||
|
||||
func (v *valueParser) ParseValue(argument string) interface{} {
|
||||
var value, err interface{}
|
||||
func NewValueParser(l *logging.Logger) ValueParser {
|
||||
return &valueParser{log: l}
|
||||
}
|
||||
|
||||
func (v *valueParser) Parse(argument string, customTag string) *yaml.Node {
|
||||
var err interface{}
|
||||
var tag = customTag
|
||||
|
||||
var inQuotes = len(argument) > 0 && argument[0] == '"'
|
||||
if !inQuotes {
|
||||
value, err = strconv.ParseFloat(argument, 64)
|
||||
if tag == "" && !inQuotes {
|
||||
|
||||
_, err = strconv.ParseBool(argument)
|
||||
if err == nil {
|
||||
return value
|
||||
tag = "!!bool"
|
||||
}
|
||||
value, err = strconv.ParseBool(argument)
|
||||
_, err = strconv.ParseFloat(argument, 64)
|
||||
if err == nil {
|
||||
return value
|
||||
tag = "!!float"
|
||||
}
|
||||
_, err = strconv.ParseInt(argument, 10, 64)
|
||||
if err == nil {
|
||||
tag = "!!int"
|
||||
}
|
||||
|
||||
if argument == "null" {
|
||||
tag = "!!null"
|
||||
}
|
||||
if argument == "[]" {
|
||||
return make([]interface{}, 0)
|
||||
return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode}
|
||||
}
|
||||
return argument
|
||||
}
|
||||
return argument[1 : len(argument)-1]
|
||||
v.log.Debugf("parsed value '%v', tag: '%v'", argument, tag)
|
||||
return &yaml.Node{Value: argument, Tag: tag, Kind: yaml.ScalarNode}
|
||||
}
|
||||
|
190
yq.go
190
yq.go
@ -29,7 +29,7 @@ var version = false
|
||||
var docIndex = "0"
|
||||
var log = logging.MustGetLogger("yq")
|
||||
var lib = yqlib.NewYqLib(log)
|
||||
var valueParser = yqlib.NewValueParser()
|
||||
var valueParser = yqlib.NewValueParser(log)
|
||||
|
||||
func main() {
|
||||
cmd := newCommandCLI()
|
||||
@ -263,28 +263,14 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
||||
for {
|
||||
var dataBucket yaml.Node
|
||||
errorReading := decoder.Decode(&dataBucket)
|
||||
log.Debugf("decoded node for doc %v", currentIndex)
|
||||
lib.DebugNode(&dataBucket)
|
||||
|
||||
if errorReading == io.EOF {
|
||||
log.Debugf("done %v / %v", currentIndex, docIndexInt)
|
||||
if !updateAll && currentIndex <= docIndexInt {
|
||||
return fmt.Errorf("asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
|
||||
}
|
||||
return nil
|
||||
return handleEOF(updateAll, docIndexInt, currentIndex)
|
||||
}
|
||||
log.Debugf("processing document %v - requested index %v", currentIndex, docIndexInt)
|
||||
if updateAll || currentIndex == docIndexInt {
|
||||
log.Debugf("reading %v in document %v", path, currentIndex)
|
||||
mappedDoc, errorParsing := lib.Get(&dataBucket, path)
|
||||
lib.DebugNode(mappedDoc)
|
||||
log.Debugf("carry on")
|
||||
if errorParsing != nil {
|
||||
return errors.Wrapf(errorParsing, "Error reading path in document index %v", currentIndex)
|
||||
} else if mappedDoc != nil {
|
||||
|
||||
mappedDocs = append(mappedDocs, mappedDoc)
|
||||
}
|
||||
|
||||
var errorParsing error
|
||||
mappedDocs, errorParsing = appendDocument(mappedDocs, dataBucket, path, updateAll, docIndexInt, currentIndex)
|
||||
if errorParsing != nil {
|
||||
return errorParsing
|
||||
}
|
||||
currentIndex = currentIndex + 1
|
||||
}
|
||||
@ -292,7 +278,38 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if errorReadingStream != nil {
|
||||
return errorReadingStream
|
||||
} else if len(mappedDocs) == 0 {
|
||||
}
|
||||
|
||||
return printResults(mappedDocs, cmd)
|
||||
}
|
||||
|
||||
func handleEOF(updateAll bool, docIndexInt int, currentIndex int) error {
|
||||
log.Debugf("done %v / %v", currentIndex, docIndexInt)
|
||||
if !updateAll && currentIndex <= docIndexInt {
|
||||
return fmt.Errorf("asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendDocument(mappedDocs []*yaml.Node, dataBucket yaml.Node, path string, updateAll bool, docIndexInt int, currentIndex int) ([]*yaml.Node, error) {
|
||||
log.Debugf("processing document %v - requested index %v", currentIndex, docIndexInt)
|
||||
lib.DebugNode(&dataBucket)
|
||||
if !updateAll && currentIndex != docIndexInt {
|
||||
return mappedDocs, nil
|
||||
}
|
||||
log.Debugf("reading %v in document %v", path, currentIndex)
|
||||
mappedDoc, errorParsing := lib.Get(&dataBucket, path)
|
||||
lib.DebugNode(mappedDoc)
|
||||
if errorParsing != nil {
|
||||
return nil, errors.Wrapf(errorParsing, "Error reading path in document index %v", currentIndex)
|
||||
} else if mappedDoc != nil {
|
||||
return append(mappedDocs, mappedDoc), nil
|
||||
}
|
||||
return mappedDocs, nil
|
||||
}
|
||||
|
||||
func printResults(mappedDocs []*yaml.Node, cmd *cobra.Command) error {
|
||||
if len(mappedDocs) == 0 {
|
||||
log.Debug("no matching results, nothing to print")
|
||||
return nil
|
||||
}
|
||||
@ -307,7 +324,7 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
||||
cmd.Println(mappedDoc.Value)
|
||||
}
|
||||
}
|
||||
} else if !updateAll {
|
||||
} else if len(mappedDocs) == 1 {
|
||||
err = encoder.Encode(mappedDocs[0])
|
||||
} else {
|
||||
err = encoder.Encode(&yaml.Node{Kind: yaml.SequenceNode, Content: mappedDocs})
|
||||
@ -319,43 +336,6 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// func newProperty(cmd *cobra.Command, args []string) error {
|
||||
// updatedData, err := newYaml(args)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// dataStr, err := toString(updatedData)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// cmd.Println(dataStr)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func newYaml(args []string) (interface{}, error) {
|
||||
// var writeCommands, writeCommandsError = readUpdateCommands(args, 2, "Must provide <path_to_update> <value>")
|
||||
// if writeCommandsError != nil {
|
||||
// return nil, writeCommandsError
|
||||
// }
|
||||
|
||||
// var dataBucket interface{}
|
||||
// var isArray = strings.HasPrefix(writeCommands[0].Key.(string), "[")
|
||||
// if isArray {
|
||||
// dataBucket = make([]interface{}, 0)
|
||||
// } else {
|
||||
// dataBucket = make(yaml.MapSlice, 0)
|
||||
// }
|
||||
|
||||
// for _, entry := range writeCommands {
|
||||
// path := entry.Key.(string)
|
||||
// value := entry.Value
|
||||
// log.Debugf("setting %v to %v", path, value)
|
||||
// dataBucket = lib.WritePath(dataBucket, path, value)
|
||||
// }
|
||||
|
||||
// return dataBucket, nil
|
||||
// }
|
||||
|
||||
func parseDocumentIndex() (bool, int, error) {
|
||||
if docIndex == "*" {
|
||||
return true, -1, nil
|
||||
@ -454,25 +434,27 @@ func prefixProperty(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
var updateData = func(dataBucket *yaml.Node, currentIndex int) error {
|
||||
if updateAll || currentIndex == docIndexInt {
|
||||
log.Debugf("Prefixing document %v", currentIndex)
|
||||
lib.DebugNode(dataBucket)
|
||||
updateCommand.Value = dataBucket.Content[0]
|
||||
dataBucket.Content = make([]*yaml.Node, 1)
|
||||
|
||||
newNode := lib.New(updateCommand.Path)
|
||||
dataBucket.Content[0] = &newNode
|
||||
|
||||
errorUpdating := lib.Update(dataBucket, updateCommand)
|
||||
if errorUpdating != nil {
|
||||
return errorUpdating
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
return prefixDocument(updateAll, docIndexInt, currentIndex, dataBucket, updateCommand)
|
||||
}
|
||||
return readAndUpdate(cmd.OutOrStdout(), args[0], updateData)
|
||||
}
|
||||
|
||||
func prefixDocument(updateAll bool, docIndexInt int, currentIndex int, dataBucket *yaml.Node, updateCommand yqlib.UpdateCommand) error {
|
||||
if updateAll || currentIndex == docIndexInt {
|
||||
log.Debugf("Prefixing document %v", currentIndex)
|
||||
lib.DebugNode(dataBucket)
|
||||
updateCommand.Value = dataBucket.Content[0]
|
||||
dataBucket.Content = make([]*yaml.Node, 1)
|
||||
|
||||
newNode := lib.New(updateCommand.Path)
|
||||
dataBucket.Content[0] = &newNode
|
||||
|
||||
errorUpdating := lib.Update(dataBucket, updateCommand)
|
||||
if errorUpdating != nil {
|
||||
return errorUpdating
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteProperty(cmd *cobra.Command, args []string) error {
|
||||
@ -506,29 +488,6 @@ func updateDoc(inputFile string, updateCommands []yqlib.UpdateCommand, writer io
|
||||
return readAndUpdate(writer, inputFile, updateData)
|
||||
}
|
||||
|
||||
// func prefixProperty(cmd *cobra.Command, args []string) error {
|
||||
// if len(args) != 2 {
|
||||
// return errors.New("Must provide <filename> <prefixed_path>")
|
||||
// }
|
||||
// prefixPath := args[1]
|
||||
|
||||
// var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
// if errorParsingDocIndex != nil {
|
||||
// return errorParsingDocIndex
|
||||
// }
|
||||
|
||||
// var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
||||
|
||||
// if updateAll || currentIndex == docIndexInt {
|
||||
// log.Debugf("Prefixing %v to doc %v", prefixPath, currentIndex)
|
||||
// var mapDataBucket = lib.PrefixPath(dataBucket, prefixPath)
|
||||
// return mapDataBucket, nil
|
||||
// }
|
||||
// return dataBucket, nil
|
||||
// }
|
||||
// return readAndUpdate(cmd.OutOrStdout(), args[0], updateData)
|
||||
// }
|
||||
|
||||
func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn) error {
|
||||
var destination io.Writer
|
||||
var destinationName string
|
||||
@ -633,42 +592,11 @@ func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string)
|
||||
log.Debug("args %v", args)
|
||||
log.Debug("path %v", args[expectedArgs-2])
|
||||
log.Debug("Value %v", args[expectedArgs-1])
|
||||
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: parseValue(args[expectedArgs-1])}
|
||||
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse(args[expectedArgs-1], customTag)}
|
||||
}
|
||||
return updateCommands, nil
|
||||
}
|
||||
|
||||
func parseValue(argument string) *yaml.Node {
|
||||
var err interface{}
|
||||
var tag = customTag
|
||||
|
||||
var inQuotes = len(argument) > 0 && argument[0] == '"'
|
||||
if tag == "" && !inQuotes {
|
||||
|
||||
_, err = strconv.ParseBool(argument)
|
||||
if err == nil {
|
||||
tag = "!!bool"
|
||||
}
|
||||
_, err = strconv.ParseFloat(argument, 64)
|
||||
if err == nil {
|
||||
tag = "!!float"
|
||||
}
|
||||
_, err = strconv.ParseInt(argument, 10, 64)
|
||||
if err == nil {
|
||||
tag = "!!int"
|
||||
}
|
||||
|
||||
if argument == "null" {
|
||||
tag = "!!null"
|
||||
}
|
||||
if argument == "[]" {
|
||||
return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode}
|
||||
}
|
||||
}
|
||||
log.Debugf("Updating node to value '%v', tag: '%v'", argument, tag)
|
||||
return &yaml.Node{Value: argument, Tag: tag, Kind: yaml.ScalarNode}
|
||||
}
|
||||
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user