summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/command/eval.go
blob: 0554cda4f2e119a9a87a47405746a876331c061c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package command

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/go-sockaddr/template"
	"github.com/mitchellh/cli"
)

type EvalCommand struct {
	Ui cli.Ui

	// debugOutput emits framed output vs raw output.
	debugOutput bool

	// flags is a list of options belonging to this command
	flags *flag.FlagSet

	// rawInput disables wrapping the string in the text/template {{ }}
	// handlebars.
	rawInput bool

	// suppressNewline changes whether or not there's a newline between each
	// arg passed to the eval subcommand.
	suppressNewline bool
}

// Description is the long-form command help.
func (c *EvalCommand) Description() string {
	return `Parse the sockaddr template and evaluates the output.

` + "The `sockaddr` library has the potential to be very complex, which is why the " +
		"`sockaddr` command supports an `eval` subcommand in order to test configurations " +
		"from the command line.  The `eval` subcommand automatically wraps its input with " +
		"the `{{` and `}}` template delimiters unless the `-r` command is specified, in " +
		"which case `eval` parses the raw input.  If the `template` argument passed to " +
		"`eval` is a dash (`-`), then `sockaddr eval` will read from stdin and " +
		"automatically sets the `-r` flag."

}

// Help returns the full help output expected by `sockaddr -h cmd`
func (c *EvalCommand) Help() string {
	return MakeHelp(c)
}

// InitOpts is responsible for setup of this command's configuration via the
// command line.  InitOpts() does not parse the arguments (see parseOpts()).
func (c *EvalCommand) InitOpts() {
	c.flags = flag.NewFlagSet("eval", flag.ContinueOnError)
	c.flags.Usage = func() { c.Ui.Output(c.Help()) }
	c.flags.BoolVar(&c.debugOutput, "d", false, "Debug output")
	c.flags.BoolVar(&c.suppressNewline, "n", false, "Suppress newlines between args")
	c.flags.BoolVar(&c.rawInput, "r", false, "Suppress wrapping the input with {{ }} delimiters")
}

// Run executes this command.
func (c *EvalCommand) Run(args []string) int {
	if len(args) == 0 {
		c.Ui.Error(c.Help())
		return 1
	}

	c.InitOpts()
	tmpls, err := c.parseOpts(args)
	if err != nil {
		if errwrap.Contains(err, "flag: help requested") {
			return 0
		}
		return 1
	}
	inputs, outputs := make([]string, len(tmpls)), make([]string, len(tmpls))
	var rawInput, readStdin bool
	for i, in := range tmpls {
		if readStdin {
			break
		}

		rawInput = c.rawInput
		if in == "-" {
			rawInput = true
			var f io.Reader = os.Stdin
			var buf bytes.Buffer
			if _, err := io.Copy(&buf, f); err != nil {
				c.Ui.Error(fmt.Sprintf("[ERROR]: Error reading from stdin: %v", err))
				return 1
			}
			in = buf.String()
			if len(in) == 0 {
				return 0
			}
			readStdin = true
		}
		inputs[i] = in

		if !rawInput {
			in = `{{` + in + `}}`
			inputs[i] = in
		}

		out, err := template.Parse(in)
		if err != nil {
			c.Ui.Error(fmt.Sprintf("ERROR[%d] in: %q\n[%d] msg: %v\n", i, in, i, err))
			return 1
		}
		outputs[i] = out
	}

	if c.debugOutput {
		for i, out := range outputs {
			c.Ui.Output(fmt.Sprintf("[%d] in: %q\n[%d] out: %q\n", i, inputs[i], i, out))
			if i != len(outputs)-1 {
				if c.debugOutput {
					c.Ui.Output(fmt.Sprintf("---\n"))
				}
			}
		}
	} else {
		sep := "\n"
		if c.suppressNewline {
			sep = ""
		}
		c.Ui.Output(strings.Join(outputs, sep))
	}

	return 0
}

// Synopsis returns a terse description used when listing sub-commands.
func (c *EvalCommand) Synopsis() string {
	return `Evaluates a sockaddr template`
}

// Usage is the one-line usage description
func (c *EvalCommand) Usage() string {
	return `sockaddr eval [options] [template ...]`
}

// VisitAllFlags forwards the visitor function to the FlagSet
func (c *EvalCommand) VisitAllFlags(fn func(*flag.Flag)) {
	c.flags.VisitAll(fn)
}

// parseOpts is responsible for parsing the options set in InitOpts().  Returns
// a list of non-parsed flags.
func (c *EvalCommand) parseOpts(args []string) ([]string, error) {
	if err := c.flags.Parse(args); err != nil {
		return nil, err
	}

	return c.flags.Args(), nil
}