github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/command/output.go (about)

     1  // Copyright 2016-2018 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package command
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/json"
    20  	"fmt"
    21  	"os"
    22  	"regexp"
    23  
    24  	"github.com/spf13/cobra"
    25  	"k8s.io/client-go/util/jsonpath"
    26  )
    27  
    28  var (
    29  	outputOpt string
    30  	re        = regexp.MustCompile(`^jsonpath\=(.*)`)
    31  )
    32  
    33  // OutputJSON returns true if the JSON output option was specified
    34  func OutputJSON() bool {
    35  	return len(outputOpt) > 0
    36  }
    37  
    38  //AddJSONOutput adds the -o|--output option to any cmd to export to json
    39  func AddJSONOutput(cmd *cobra.Command) {
    40  	cmd.Flags().StringVarP(&outputOpt, "output", "o", "", "json| jsonpath='{}'")
    41  }
    42  
    43  //PrintOutput receives an interface and dump the data using the --output flag.
    44  //ATM only json or jsonpath. In the future yaml
    45  func PrintOutput(data interface{}) error {
    46  	return PrintOutputWithType(data, outputOpt)
    47  }
    48  
    49  //PrintOutputWithType receives an interface and dump the data using the --output flag.
    50  //ATM only json or jsonpath. In the future yaml
    51  func PrintOutputWithType(data interface{}, outputType string) error {
    52  	if outputType == "json" {
    53  		return dumpJSON(data, "")
    54  	}
    55  
    56  	if re.MatchString(outputType) {
    57  		return dumpJSON(data, re.ReplaceAllString(outputType, "$1"))
    58  	}
    59  
    60  	return fmt.Errorf("couldn't found output printer")
    61  }
    62  
    63  // DumpJSONToSlice dumps the contents of data into a byte slice. If jsonpath
    64  // is non-empty, will attempt to do jsonpath filtering using said string.
    65  // Returns byte array containing the JSON in data, or an error if any JSON
    66  // marshaling, parsing operations fail.
    67  func DumpJSONToSlice(data interface{}, jsonPath string) ([]byte, error) {
    68  	if len(jsonPath) == 0 {
    69  		result, err := json.MarshalIndent(data, "", "  ")
    70  		if err != nil {
    71  			fmt.Fprintf(os.Stderr, "Couldn't marshal to json: '%s'\n", err)
    72  			return nil, err
    73  		}
    74  		fmt.Println(string(result))
    75  		return nil, nil
    76  	}
    77  
    78  	parser := jsonpath.New("").AllowMissingKeys(true)
    79  	if err := parser.Parse(jsonPath); err != nil {
    80  		fmt.Fprintf(os.Stderr, "Couldn't parse jsonpath expression: '%s'\n", err)
    81  		return nil, err
    82  	}
    83  
    84  	buf := new(bytes.Buffer)
    85  	if err := parser.Execute(buf, data); err != nil {
    86  		fmt.Fprintf(os.Stderr, "Couldn't parse jsonpath expression: '%s'\n", err)
    87  		return nil, err
    88  
    89  	}
    90  	return buf.Bytes(), nil
    91  }
    92  
    93  // dumpJSON dump the data variable to the stdout as json.
    94  // If somethings fail, it'll return an error
    95  // If jsonPath is passed, it'll run the json query over data var.
    96  func dumpJSON(data interface{}, jsonPath string) error {
    97  	jsonBytes, err := DumpJSONToSlice(data, jsonPath)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	fmt.Println(string(jsonBytes[:]))
   102  	return nil
   103  }