Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance added evars validation #547

Merged
merged 3 commits into from
Aug 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 43 additions & 25 deletions commands/evar/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package evar

import (
"fmt"
"io/ioutil"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -44,36 +44,54 @@ func addFn(ccmd *cobra.Command, args []string) {
}
}

// parseEvars parses evars already split into key="val" pairs.
func parseEvars(args []string) map[string]string {
evars := map[string]string{}

for _, arg := range args {
// define a function that will allow us to
// split on ',' or ' '
f := func(c rune) bool {
return c == ','
}

for _, pair := range strings.FieldsFunc(arg, f) {
// define a field split that llows us to split on
// ':' or '='

// todo: return after first split (in case there are `=` in the variable)
// parts := strings.FieldsFunc(pair, func(c rune) bool {
// return c == '='
// })
for _, pair := range args {
// return after first split (in case there are `=` in the variable)
parts := strings.SplitN(pair, "=", 2)
if len(parts) == 2 {
if parts[0] == "" {
fmt.Printf(`
--------------------------------------------
Please provide a key to add evar!
--------------------------------------------`)
continue
}
part := parts[1]
var err error
// if we've quoted the variable, and it's not a multiline, un-escape it
if (len(parts[1]) > 1 && parts[1][0] == '"') && !strings.Contains(part, "\n") {
// un-escape string values ("ensures proper escaped values too")
// part, err = strconv.Unquote(strconv.Quote(parts[1]))
part, err = strconv.Unquote(parts[1])
if err != nil {
fmt.Printf(`
--------------------------------------------
Please provide a properly escaped value!
--------------------------------------------`)
continue
}
} else { // else, it's likely a multiline and we'll need to just remove quotes
// strip var leading quote
if parts[1][0] == '"' && len(parts[1]) > 1 {
parts[1] = parts[1][1:]
}

parts := strings.SplitN(pair, "=", 2)
if len(parts) == 2 {
// check to see if the value is a file
content, err := ioutil.ReadFile(parts[1])
if err == nil {
parts[1] = string(content)
// strip var ending quote
if parts[1][len(parts[1])-1] == '"' && len(parts[1]) > 1 {
parts[1] = parts[1][:len(parts[1])-1]
}
evars[strings.ToUpper(parts[0])] = parts[1]
} else {
fmt.Printf("invalid evar (%s)\n", pair)
part = parts[1]
}

evars[strings.ToUpper(parts[0])] = part
} else {
fmt.Printf(`
--------------------------------------------
Please provide a valid evar! ("key=value")
--------------------------------------------`)
}
}

Expand Down
32 changes: 29 additions & 3 deletions commands/evar/evar_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,36 @@ import (
"testing"
)

// TestEvarAdd tests the adding of environment variables from the cli.
func TestEvarAdd(t *testing.T) {
vars := []string{`key="this
is
a
multiline
"`, "key2=val", "key3=\"this\nis\na\nmultiline too\""}
evars := parseEvars(vars)

if len(evars) != 3 {
t.Fatalf("Failed to parse all evars - %d - %q", len(evars), evars)
}

if evars["KEY"] != "this\nis\na\nmultiline\n" {
t.Fatalf("multiline var failed - %q", evars["KEY"])
}

if evars["KEY2"] != "val" {
t.Fatalf("Commas, spaces, = var failed - %q", evars["KEY2"])
}

if evars["KEY3"] != "this\nis\na\nmultiline too" {
t.Fatalf("Single quote, semicolon var failed - %q", evars["KEY3"])
}
}

// TestEvarLoad tests the loading of environment variables from a file.
func TestEvarLoad(t *testing.T) {
vars, _ := loadVars([]string{""}, testGetter{})
evars := parseSplitEvars(vars)
evars := parseEvars(vars)

if len(evars) != 11 {
t.Fatalf("Failed to parse all evars - %d - %q", len(evars), evars)
Expand All @@ -21,7 +47,7 @@ func TestEvarLoad(t *testing.T) {
t.Fatalf("Commas, spaces, = var failed - %q", evars["KEY5"])
}

if evars["KEY9"] != "you're welcome ;)" {
if evars["KEY9"] != "you're \"welcome ;)" {
t.Fatalf("Single quote, semicolon var failed - %q", evars["KEY9"])
}

Expand Down Expand Up @@ -54,7 +80,7 @@ export key7="how is this guy doing these awesome things"


key8="yep, even whitespace is _allowed (gets stripped)"
export key9="you're welcome ;)"
export key9="you're \"welcome ;)"
key10="x"
key_11="x
y
Expand Down
30 changes: 2 additions & 28 deletions commands/evar/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func loadFn(ccmd *cobra.Command, args []string) {
return
}

evars := parseSplitEvars(vars)
evars := parseEvars(vars)

switch location {
case "local":
Expand Down Expand Up @@ -80,7 +80,7 @@ func loadVars(args []string, getter contentGetter) ([]string, error) {
start := 0
for i := range indexes {
end := indexes[i][0]
if end == 0 {
if end <= 2 {
continue
}
// end-1 leaves off the newline after the variable declaration
Expand All @@ -94,32 +94,6 @@ func loadVars(args []string, getter contentGetter) ([]string, error) {
return vars, nil
}

// parseSplitEvars parses evars already split into key="val" pairs.
func parseSplitEvars(vars []string) map[string]string {
evars := map[string]string{}

for _, pair := range vars {
parts := strings.SplitN(pair, "=", 2)
if len(parts) == 2 {
// strip var leading quote
if parts[1][0] == '"' && len(parts[1]) > 1 {
parts[1] = parts[1][1:]
}

// strip var ending quote
if parts[1][len(parts[1])-1] == '"' && len(parts[1]) > 1 {
parts[1] = parts[1][:len(parts[1])-1]
}

evars[strings.ToUpper(parts[0])] = parts[1]
} else {
fmt.Printf("invalid evar (%s)\n", pair)
}
}

return evars
}

// contentGetter is an interface to allow us to test loading/parsing of variables.
type contentGetter interface {
getContents(filename string) (string, error)
Expand Down
4 changes: 1 addition & 3 deletions commands/evar/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ func parseKeys(args []string) []string {

for _, arg := range args {
for _, key := range strings.Split(arg, ",") {
if key != "" {
keys = append(keys, strings.ToUpper(key))
}
keys = append(keys, strings.ToUpper(key))
}
}

Expand Down