yq/cmd/evaluate_reduce_command.go
2021-07-24 15:21:53 +10:00

113 lines
3.2 KiB
Go

package cmd
import (
"errors"
"fmt"
"os"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
)
func createEvaluateReduceCommand() *cobra.Command {
var cmdEvalReduce = &cobra.Command{
Use: "eval-reduce [reduce expression] [yaml_file1]...",
Aliases: []string{"er"},
Short: "Runs a reduce expression sequentially against each document of each file given. More memory efficient than using eval-all if you can get away with it.",
Example: `
# Merge f2.yml into f1.yml (inplace)
yq eval-reduce --inplace '{} ; . * $doc' f1.yml f2.yml
`,
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.
## Evaluate Reduce ##
This command runs the reduce expression against each document of each file given, accumulating the results.
It is most useful when merging multiple files (but isn't as flexible as using eval-all with ireduce, as you
can only merge the top level nodes).
`,
RunE: evaluateReduce,
}
return cmdEvalReduce
}
func evaluateReduce(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
// 2+ args, [0] = expression, file the rest
var err error
out := cmd.OutOrStdout()
fileInfo, _ := os.Stdout.Stat()
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
colorsEnabled = true
}
firstFileIndex := -1
if !nullInput && len(args) == 1 {
firstFileIndex = 0
} else if len(args) > 1 {
firstFileIndex = 1
}
if writeInplace && (firstFileIndex == -1) {
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
}
if writeInplace {
// only use colors if its forced
colorsEnabled = forceColor
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[firstFileIndex])
out, err = writeInPlaceHandler.CreateTempFile()
if err != nil {
return err
}
// need to indirectly call the function so that completedSuccessfully is
// passed when we finish execution as opposed to now
defer func() { writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully) }()
}
if nullInput && len(args) > 1 {
return errors.New("Cannot pass files in when using null-input flag")
}
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
if frontMatter != "" {
frontMatterHandler := yqlib.NewFrontMatterHandler(args[firstFileIndex])
err = frontMatterHandler.Split()
if err != nil {
return err
}
args[firstFileIndex] = frontMatterHandler.GetYamlFrontMatterFilename()
if frontMatter == "process" {
reader := frontMatterHandler.GetContentReader()
printer.SetAppendix(reader)
defer yqlib.SafelyCloseReader(reader)
}
defer frontMatterHandler.CleanUp()
}
reduceEvaluator := yqlib.NewReduceEvaluator()
switch len(args) {
case 0:
cmd.Println(cmd.UsageString())
return nil
case 1:
cmd.Println(cmd.UsageString())
return nil
default:
err = reduceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing)
}
completedSuccessfully = err == nil
if err == nil && exitStatus && !printer.PrintedAnything() {
return errors.New("no matches found")
}
return err
}