1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/cmd/cli/kubectl-kyverno/commands/jp/parse/command.go
Charles-Edouard Brétéché dc71610df7
refactor: cli commands tests and error handling (#8367)
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
2023-09-13 09:53:19 +00:00

100 lines
2.8 KiB
Go

package parse
import (
"fmt"
"io"
"os"
"path/filepath"
gojmespath "github.com/kyverno/go-jmespath"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
"github.com/spf13/cobra"
)
func Command() *cobra.Command {
var files []string
cmd := &cobra.Command{
Use: "parse [-f file|expression]...",
Short: command.FormatDescription(true, websiteUrl, false, description...),
Long: command.FormatDescription(false, websiteUrl, false, description...),
Example: command.FormatExamples(examples...),
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
expressions, err := loadExpressions(cmd, args, files)
if err != nil {
return err
}
for _, expression := range expressions {
if err := printAst(cmd.OutOrStdout(), expression); err != nil {
return err
}
}
return nil
},
}
cmd.Flags().StringSliceVarP(&files, "file", "f", nil, "Read input from a JSON or YAML file instead of stdin")
return cmd
}
func readFile(reader io.Reader) (string, error) {
data, err := io.ReadAll(reader)
if err != nil {
return "", err
}
return string(data), nil
}
func loadFile(cmd *cobra.Command, file string) (string, error) {
reader, err := os.Open(filepath.Clean(file))
if err != nil {
return "", fmt.Errorf("failed open file %s: %v", file, err)
}
defer func() {
if err := reader.Close(); err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "Error closing file: %s\n", err)
}
}()
content, err := readFile(reader)
if err != nil {
return "", fmt.Errorf("failed read file %s: %v", file, err)
}
return content, nil
}
func loadExpressions(cmd *cobra.Command, args []string, files []string) ([]string, error) {
var expressions []string
expressions = append(expressions, args...)
for _, file := range files {
expression, err := loadFile(cmd, file)
if err != nil {
return nil, err
}
expressions = append(expressions, expression)
}
if len(expressions) == 0 {
fmt.Fprintln(cmd.OutOrStdout(), "Reading from terminal input.")
fmt.Fprintln(cmd.OutOrStdout(), "Enter a jmespath expression and hit Ctrl+D.")
data, err := readFile(cmd.InOrStdin())
if err != nil {
return nil, fmt.Errorf("failed to read file STDIN: %v", err)
}
expressions = append(expressions, data)
}
return expressions, nil
}
// The following function has been adapted from
// https://github.com/jmespath/jp/blob/54882e03bd277fc4475a677fab1d35eaa478b839/jp.go
func printAst(out io.Writer, expression string) error {
parser := gojmespath.NewParser()
parsed, err := parser.Parse(expression)
if err != nil {
if syntaxError, ok := err.(gojmespath.SyntaxError); ok {
return fmt.Errorf("%w\n%s", syntaxError, syntaxError.HighlightLocation())
}
return err
}
fmt.Fprintln(out, "#", expression)
fmt.Fprintln(out, parsed)
return nil
}