Use cobra for cli for nicer cli-ness

This commit is contained in:
mfarah 2015-10-06 16:07:09 +11:00
parent 1605938c2c
commit 1d5fbd5ad0
3 changed files with 70 additions and 63 deletions

View File

@ -12,7 +12,7 @@ go get github.com/mikefarah/yaml
## Read examples ## Read examples
``` ```
yaml <yaml file> <path> yaml r <yaml file> <path>
``` ```
### Basic ### Basic
@ -23,14 +23,14 @@ b:
``` ```
then then
```bash ```bash
yaml sample.yaml b.c yaml r sample.yaml b.c
``` ```
will output the value of '2'. will output the value of '2'.
### Reading from STDIN ### Reading from STDIN
Given a sample.yaml file of: Given a sample.yaml file of:
```bash ```bash
cat sample.yaml | yaml - b.c cat sample.yaml | yaml r - b.c
``` ```
will output the value of '2'. will output the value of '2'.
@ -46,7 +46,7 @@ bob:
``` ```
then then
```bash ```bash
yaml sample.yaml bob.*.cats yaml r sample.yaml bob.*.cats
``` ```
will output will output
```yaml ```yaml
@ -62,7 +62,7 @@ b.x:
``` ```
then then
```bash ```bash
yaml sample.yaml \"b.x\".c yaml r sample.yaml \"b.x\".c
``` ```
will output the value of '2'. will output the value of '2'.
@ -79,7 +79,7 @@ b:
``` ```
then then
``` ```
yaml sample.yaml b.e[1].name yaml r sample.yaml b.e[1].name
``` ```
will output 'sam' will output 'sam'
@ -95,7 +95,7 @@ b:
``` ```
then then
``` ```
yaml sample.yaml b.e[*].name yaml r sample.yaml b.e[*].name
``` ```
will output: will output:
``` ```
@ -121,7 +121,6 @@ b:
c: cat c: cat
``` ```
### Updating yaml in-place ### Updating yaml in-place
Given a sample.yaml file of: Given a sample.yaml file of:
```yaml ```yaml
@ -130,6 +129,6 @@ b:
``` ```
then then
```bash ```bash
yaml wi sample.yaml b.c cat yaml w -i sample.yaml b.c cat
``` ```
will update the sample.yaml file so that the value of 'c' is cat. will update the sample.yaml file so that the value of 'c' is cat.

View File

@ -6,7 +6,7 @@ go test
# acceptance test # acceptance test
go build go build
X=$(./yaml sample.yaml b.c) X=$(./yaml r sample.yaml b.c)
if [ $X != 2 ] if [ $X != 2 ]
then then

110
yaml.go
View File

@ -2,7 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/codegangsta/cli" "github.com/spf13/cobra"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"io/ioutil" "io/ioutil"
"log" "log"
@ -11,74 +11,79 @@ import (
"strings" "strings"
) )
var trimOutput = true
var writeInplace = false
func main() { func main() {
app := cli.NewApp() var cmdRead = &cobra.Command{
app.Name = "yaml" Use: "read [yaml_file] [path]",
app.Usage = "command line tool for reading and writing yaml"
app.Commands = []cli.Command{
{
Name: "read",
Aliases: []string{"r"}, Aliases: []string{"r"},
Usage: "read <filename> <path>\n\te.g.: yaml read sample.yaml a.b.c\n\t(default) reads a property from a given yaml file\n", Short: "yaml r sample.yaml a.b.c",
Action: readProperty, Example: `
}, yaml read things.yaml a.b.c
{ yaml r - a.b.c (reads from stdin)
Name: "write", yaml r things.yaml a.*.c
Aliases: []string{"w"}, yaml r things.yaml a.array[0].blah
Usage: "write <filename> <path> <value>\n\te.g.: yaml write sample.yaml a.b.c 5\n\tupdates a property from a given yaml file, outputs to stdout\n", yaml r things.yaml a.array[*].blah
Action: writeProperty, `,
}, Long: "Outputs the value of the given path in the yaml file to STDOUT",
{ Run: readProperty,
Name: "write-inplace",
Aliases: []string{"wi"},
Usage: "wi <filename> <path> <value>\n\te.g.: yaml wi sample.yaml a.b.c 5\n\tupdates a property from a given yaml file and saves it to the given filename (sample.yaml)\n",
Action: writePropertyInPlace,
},
} }
app.Action = readProperty
app.Run(os.Args) var cmdWrite = &cobra.Command{
Use: "write [yaml_file] [path] [value]",
Aliases: []string{"w"},
Short: "yaml w [--inplace/-i] sample.yaml a.b.c newValueForC",
Example: `
yaml write things.yaml a.b.c cat
yaml write --inplace things.yaml a.b.c cat
yaml w -i things.yaml a.b.c cat
`,
Long: `Updates the yaml file w.r.t the given path and value.
Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.`,
Run: writeProperty,
}
cmdWrite.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
var rootCmd = &cobra.Command{Use: "yaml"}
rootCmd.PersistentFlags().BoolVarP(&trimOutput, "trim", "t", true, "trim yaml output")
rootCmd.AddCommand(cmdRead, cmdWrite)
rootCmd.Execute()
} }
func readProperty(c *cli.Context) { func readProperty(cmd *cobra.Command, args []string) {
var parsedData map[interface{}]interface{} var parsedData map[interface{}]interface{}
readYaml(c, &parsedData) readYaml(args, &parsedData)
if len(c.Args()) == 1 { if len(args) == 1 {
printYaml(parsedData) printYaml(parsedData)
os.Exit(0) os.Exit(0)
} }
var paths = parsePath(c.Args()[1]) var paths = parsePath(args[1])
printYaml(readMap(parsedData, paths[0], paths[1:len(paths)])) printYaml(readMap(parsedData, paths[0], paths[1:len(paths)]))
} }
func writeProperty(c *cli.Context) { func writeProperty(cmd *cobra.Command, args []string) {
printYaml(updateProperty(c)) if len(args) < 3 {
}
func writePropertyInPlace(c *cli.Context) {
updatedYaml := updateProperty(c)
ioutil.WriteFile(c.Args()[0], []byte(updatedYaml), 0644)
}
func updateProperty(c *cli.Context) string {
var parsedData map[interface{}]interface{}
readYaml(c, &parsedData)
if len(c.Args()) < 3 {
log.Fatalf("Must provide <filename> <path_to_update> <value>") log.Fatalf("Must provide <filename> <path_to_update> <value>")
} }
var paths = parsePath(c.Args()[1]) var parsedData map[interface{}]interface{}
readYaml(args, &parsedData)
write(parsedData, paths[0], paths[1:len(paths)], getValue(c.Args()[2])) var paths = parsePath(args[1])
return yamlToString(parsedData) write(parsedData, paths[0], paths[1:len(paths)], getValue(args[2]))
if writeInplace {
ioutil.WriteFile(args[0], []byte(yamlToString(parsedData)), 0644)
} else {
printYaml(parsedData)
}
} }
func getValue(argument string) interface{} { func getValue(argument string) interface{} {
var value, err interface{} var value, err interface{}
var inQuotes = argument[0] == '"' var inQuotes = argument[0] == '"'
@ -108,19 +113,22 @@ func yamlToString(context interface{}) string {
outStr := string(out) outStr := string(out)
// trim the trailing new line as it's easier for a script to add // trim the trailing new line as it's easier for a script to add
// it in if required than to remove it // it in if required than to remove it
if trimOutput {
return strings.Trim(outStr, "\n ") return strings.Trim(outStr, "\n ")
}
return outStr
} }
func readYaml(c *cli.Context, parsedData *map[interface{}]interface{}) { func readYaml(args []string, parsedData *map[interface{}]interface{}) {
if len(c.Args()) == 0 { if len(args) == 0 {
log.Fatalf("Must provide filename") log.Fatalf("Must provide filename")
} }
var rawData []byte var rawData []byte
if c.Args()[0] == "-" { if args[0] == "-" {
rawData = readStdin() rawData = readStdin()
} else { } else {
rawData = readFile(c.Args()[0]) rawData = readFile(args[0])
} }
err := yaml.Unmarshal([]byte(rawData), &parsedData) err := yaml.Unmarshal([]byte(rawData), &parsedData)