diff --git a/lib/output/invalid.go b/lib/output/invalid.go new file mode 100644 index 0000000..9accee4 --- /dev/null +++ b/lib/output/invalid.go @@ -0,0 +1,13 @@ +package output + +import ( + "fmt" +) + +type InvalidOutput struct { + Config Config +} + +func (o *InvalidOutput) GenerateOutput(elements interface{}) (string, error) { + return "", fmt.Errorf("Unrecognized output format: %s", o.Config.Format) +} diff --git a/lib/output/json.go b/lib/output/json.go new file mode 100644 index 0000000..c724272 --- /dev/null +++ b/lib/output/json.go @@ -0,0 +1,30 @@ +package output + +import ( + "encoding/json" + "fmt" +) + +type JSONOutput struct { + Config Config +} + +func (o *JSONOutput) GenerateOutput(elements interface{}) (string, error) { + if _, ok := elements.([]interface{}); ok { + if j, err := json.MarshalIndent(elements, " ", " "); err != nil { + return "", err + } else { + return string(j), nil + } + } else { + if _, ok := elements.(map[string]interface{}); ok { + if j, err := json.MarshalIndent(elements, " ", " "); err != nil { + return "", err + } else { + return string(j), nil + } + } else { + return fmt.Sprintf("%s", elements), nil + } + } +} diff --git a/lib/output/output.go b/lib/output/output.go index a2345b4..3b8bed1 100644 --- a/lib/output/output.go +++ b/lib/output/output.go @@ -1,11 +1,8 @@ package output -import ( - "encoding/json" - "fmt" - "sort" - "strings" -) +type OutputBuilder interface { + GenerateOutput(interface{}) (string, error) +} type Config struct { Format string @@ -20,111 +17,21 @@ func (o *Output) Generate(elements interface{}) (string, error) { return "", nil } + var v OutputBuilder switch o.Config.Format { case "json": - return o.JSONOutput(elements) - case "shell": - return o.ShellOutput(elements) - } - - return "", fmt.Errorf("Unrecognized output format: %s", o.Config.Format) -} - -func (o *Output) JSONOutput(elements interface{}) (string, error) { - if _, ok := elements.([]interface{}); ok { - if j, err := json.MarshalIndent(elements, " ", " "); err != nil { - return "", err - } else { - return string(j), nil - } - } else { - if _, ok := elements.(map[string]interface{}); ok { - if j, err := json.MarshalIndent(elements, " ", " "); err != nil { - return "", err - } else { - return string(j), nil - } - } else { - return fmt.Sprintf("%s", elements), nil - } - } -} - -func (o *Output) ShellOutput(elements interface{}) (string, error) { - var keys []string - var output string - - parsed := make(map[string]string) - _, _, parsed = parseElementsForShell("elements", elements, parsed) - - for k := range parsed { - keys = append(keys, k) - } - - sort.Strings(keys) - - for _, k := range keys { - output = fmt.Sprintf("%s%s=\"%s\"\n", output, k, parsed[k]) - } - - return output, nil -} - -func parseElementsForShell(label string, elements interface{}, parsed map[string]string) (string, interface{}, map[string]string) { - var e interface{} - switch elements.(type) { - case map[string]interface{}: - for key, subElements := range elements.(map[string]interface{}) { - l := fmt.Sprintf("%s_%s", label, sanitizeKeyForShell(key)) - _, e, parsed = parseElementsForShell(l, subElements, parsed) + v = &JSONOutput{ + Config: o.Config, } - case []interface{}: - for i, subElements := range elements.([]interface{}) { - l := fmt.Sprintf("%s_%d", label, i) - _, e, parsed = parseElementsForShell(l, subElements, parsed) + case "shell": + v = &ShellOutput{ + Config: o.Config, } default: - parsed[label] = fmt.Sprintf("%v", elements) - return label, nil, parsed + v = &InvalidOutput{ + Config: o.Config, + } } - return label, e, parsed -} - -func sanitizeKeyForShell(key string) string { - // replace non-compliant shell characters with underscores, - // per IEEE Std 1003.1-2001 - r := strings.NewReplacer( - "`", "_", - "~", "_", - "!", "_", - "@", "_", - "#", "_", - "$", "_", - "%", "_", - "^", "_", - "&", "_", - "*", "_", - "(", "_", - ")", "_", - "-", "_", - "+", "_", - "=", "_", - "{", "_", - "}", "_", - "[", "_", - "]", "_", - "|", "_", - ":", "_", - ";", "_", - "'", "_", - "\"", "_", - "/", "_", - "?", "_", - ",", "_", - ".", "_", - "<", "_", - ">", "_", - ) - return r.Replace(key) + return v.GenerateOutput(elements) } diff --git a/lib/output/shell.go b/lib/output/shell.go new file mode 100644 index 0000000..030601d --- /dev/null +++ b/lib/output/shell.go @@ -0,0 +1,90 @@ +package output + +import ( + "fmt" + "sort" + "strings" +) + +type ShellOutput struct { + Config Config +} + +func (o *ShellOutput) GenerateOutput(elements interface{}) (string, error) { + var keys []string + var output string + + parsed := make(map[string]string) + _, _, parsed = parseElementsForShell("elements", elements, parsed) + + for k := range parsed { + keys = append(keys, k) + } + + sort.Strings(keys) + + for _, k := range keys { + output = fmt.Sprintf("%s%s=\"%s\"\n", output, k, parsed[k]) + } + + return output, nil +} + +func parseElementsForShell(label string, elements interface{}, parsed map[string]string) (string, interface{}, map[string]string) { + var e interface{} + switch elements.(type) { + case map[string]interface{}: + for key, subElements := range elements.(map[string]interface{}) { + l := fmt.Sprintf("%s_%s", label, sanitizeKeyForShell(key)) + _, e, parsed = parseElementsForShell(l, subElements, parsed) + } + case []interface{}: + for i, subElements := range elements.([]interface{}) { + l := fmt.Sprintf("%s_%d", label, i) + _, e, parsed = parseElementsForShell(l, subElements, parsed) + } + default: + parsed[label] = fmt.Sprintf("%v", elements) + return label, nil, parsed + } + + return label, e, parsed +} + +func sanitizeKeyForShell(key string) string { + // replace non-compliant shell characters with underscores, + // per IEEE Std 1003.1-2001 + r := strings.NewReplacer( + "`", "_", + "~", "_", + "!", "_", + "@", "_", + "#", "_", + "$", "_", + "%", "_", + "^", "_", + "&", "_", + "*", "_", + "(", "_", + ")", "_", + "-", "_", + "+", "_", + "=", "_", + "{", "_", + "}", "_", + "[", "_", + "]", "_", + "|", "_", + ":", "_", + ";", "_", + "'", "_", + "\"", "_", + "/", "_", + "?", "_", + ",", "_", + ".", "_", + "<", "_", + ">", "_", + ) + return r.Replace(key) +}