github.com/neilotoole/jsoncolor@v0.6.0/cmd/jc/main.go (about) 1 // Package main contains a trivial CLI that accepts JSON input either 2 // via stdin or via "-i path/to/input.json", and outputs JSON 3 // to stdout, or if "-o path/to/output.json" is set, outputs to that file. 4 // If -c (colorized) is true, output to stdout will be colorized if possible 5 // (but never colorized for file output). 6 // 7 // Examples: 8 // 9 // $ cat example.json | jc 10 // $ cat example.json | jc -c false 11 12 package main 13 14 import ( 15 "errors" 16 "flag" 17 "fmt" 18 "io" 19 "io/ioutil" 20 "os" 21 "path/filepath" 22 23 "github.com/mattn/go-colorable" 24 json "github.com/neilotoole/jsoncolor" 25 ) 26 27 var ( 28 flagPretty = flag.Bool("p", true, "output pretty JSON") 29 flagColorize = flag.Bool("c", true, "output colorized JSON") 30 flagInputFile = flag.String("i", "", "path to input JSON file") 31 flagOutputFile = flag.String("o", "", "path to output JSON file") 32 ) 33 34 func printUsage() { 35 const msg = ` 36 jc (jsoncolor) is a trivial CLI to demonstrate the neilotoole/jsoncolor package. 37 It accepts JSON input, and outputs colorized, prettified JSON. 38 39 Example Usage: 40 41 # Pipe a JSON file, using defaults (colorized and prettified); print to stdout 42 $ cat testdata/sakila_actor.json | jc 43 44 # Read input from a JSON file, print to stdout, DO colorize but DO NOT prettify 45 $ jc -c -p=false -i ./testdata/sakila_actor.json 46 47 # Pipe a JSON input file to jc, outputting to a specified file; and DO NOT prettify 48 $ cat ./testdata/sakila_actor.json | jc -p=false -o /tmp/out.json 49 ` 50 fmt.Fprintf(os.Stderr, msg) 51 } 52 53 func main() { 54 flag.Parse() 55 if err := doMain(); err != nil { 56 fmt.Fprintf(os.Stderr, "error: %v\n", err) 57 printUsage() 58 os.Exit(1) 59 } 60 } 61 62 func doMain() error { 63 var ( 64 input []byte 65 err error 66 ) 67 68 if flagInputFile != nil && *flagInputFile != "" { 69 // Read from file 70 var f *os.File 71 if f, err = os.Open(*flagInputFile); err != nil { 72 return err 73 } 74 defer f.Close() 75 76 if input, err = ioutil.ReadAll(f); err != nil { 77 return err 78 } 79 } else { 80 // Probably read from stdin... 81 var fi os.FileInfo 82 if fi, err = os.Stdin.Stat(); err != nil { 83 return err 84 } 85 86 if (fi.Mode() & os.ModeCharDevice) == 0 { 87 // Read from stdin 88 if input, err = ioutil.ReadAll(os.Stdin); err != nil { 89 return err 90 } 91 } else { 92 return errors.New("invalid args") 93 } 94 } 95 96 jsn := new(interface{}) // generic interface{} that will hold the parsed JSON 97 if err = json.Unmarshal(input, jsn); err != nil { 98 return fmt.Errorf("invalid input JSON: %w", err) 99 } 100 101 var out io.Writer 102 if flagOutputFile != nil && *flagOutputFile != "" { 103 // Output file is specified via -o flag 104 var fpath string 105 if fpath, err = filepath.Abs(*flagOutputFile); err != nil { 106 return fmt.Errorf("failed to get absolute path for -o %q: %w", *flagOutputFile, err) 107 } 108 109 // Ensure the parent dir exists 110 if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { 111 return fmt.Errorf("failed to make parent dir for -o %q: %w", *flagOutputFile, err) 112 } 113 114 var f *os.File 115 if f, err = os.Create(fpath); err != nil { 116 return fmt.Errorf("failed to open output file specified by -o %q: %w", *flagOutputFile, err) 117 } 118 defer f.Close() 119 out = f 120 } else { 121 // Output file NOT specified via -o flag, use stdout. 122 out = os.Stdout 123 } 124 125 var enc *json.Encoder 126 127 if flagColorize != nil && *flagColorize == true && json.IsColorTerminal(out) { 128 out = colorable.NewColorable(out.(*os.File)) // colorable is needed for Windows 129 enc = json.NewEncoder(out) 130 clrs := json.DefaultColors() 131 enc.SetColors(clrs) 132 } else { 133 // We are NOT doing color output: either flag not set, or we 134 // could be outputting to a file etc. 135 // Therefore DO NOT call enc.SetColors. 136 enc = json.NewEncoder(out) 137 } 138 139 if flagPretty != nil && *flagPretty == true { 140 // Pretty-print, i.e. set indent 141 enc.SetIndent("", " ") 142 } 143 144 if err = enc.Encode(jsn); err != nil { 145 return err 146 } 147 148 return nil 149 }