Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
159 lines (134 sloc) 4 KB
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
}
You can’t perform that action at this time.