| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| package cmd |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "os" |
| "reflect" |
| "sort" |
| "strings" |
| "text/tabwriter" |
| |
| "github.com/apache/cloudstack-cloudmonkey/config" |
| "github.com/olekukonko/tablewriter" |
| ) |
| |
| func jsonify(value interface{}, format string) string { |
| if value == nil { |
| return "" |
| } |
| if reflect.TypeOf(value).Kind() == reflect.Map || reflect.TypeOf(value).Kind() == reflect.Slice { |
| var jsonStr []byte |
| var err error |
| if format == "text" { |
| jsonStr, err = json.MarshalIndent(value, "", "") |
| } else { |
| jsonStr, err = json.Marshal(value) |
| } |
| if err == nil { |
| value = string(jsonStr) |
| } |
| } |
| switch value.(type) { |
| case float64, float32: |
| return fmt.Sprintf("%.f", value) |
| default: |
| return fmt.Sprintf("%v", value) |
| } |
| } |
| |
| func printJSON(response map[string]interface{}) { |
| enc := json.NewEncoder(os.Stdout) |
| enc.SetEscapeHTML(false) |
| enc.SetIndent("", " ") |
| enc.Encode(response) |
| } |
| |
| func printText(response map[string]interface{}) { |
| format := "text" |
| for k, v := range response { |
| valueType := reflect.TypeOf(v) |
| if valueType.Kind() == reflect.Slice { |
| fmt.Printf("%v:\n", k) |
| for idx, item := range v.([]interface{}) { |
| if idx > 0 { |
| fmt.Println("================================================================================") |
| } |
| row, isMap := item.(map[string]interface{}) |
| if isMap { |
| for field, value := range row { |
| fmt.Printf("%s = %v\n", field, jsonify(value, format)) |
| } |
| } else { |
| fmt.Printf("%v\n", item) |
| } |
| } |
| } else { |
| fmt.Printf("%v = %v\n", k, jsonify(v, format)) |
| } |
| } |
| } |
| |
| func printTable(response map[string]interface{}, filter []string) { |
| format := "table" |
| table := tablewriter.NewWriter(os.Stdout) |
| for k, v := range response { |
| valueType := reflect.TypeOf(v) |
| if valueType.Kind() == reflect.Slice { |
| items, ok := v.([]interface{}) |
| if !ok { |
| continue |
| } |
| fmt.Printf("%v:\n", k) |
| var header []string |
| for _, item := range items { |
| row, ok := item.(map[string]interface{}) |
| if !ok || len(row) < 1 { |
| continue |
| } |
| if len(header) == 0 { |
| if len(filter) > 0 { |
| header = filter |
| } else { |
| for field := range row { |
| header = append(header, field) |
| } |
| sort.Strings(header) |
| } |
| table.SetHeader(header) |
| } |
| var rowArray []string |
| for _, field := range header { |
| rowArray = append(rowArray, jsonify(row[field], format)) |
| } |
| table.Append(rowArray) |
| } |
| } else { |
| fmt.Printf("%v = %v\n", k, v) |
| } |
| } |
| table.Render() |
| } |
| |
| func printColumn(response map[string]interface{}, filter []string) { |
| format := "column" |
| w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', tabwriter.DiscardEmptyColumns) |
| for _, v := range response { |
| valueType := reflect.TypeOf(v) |
| if valueType.Kind() == reflect.Slice || valueType.Kind() == reflect.Map { |
| items, ok := v.([]interface{}) |
| if !ok { |
| continue |
| } |
| var header []string |
| for idx, item := range items { |
| row, ok := item.(map[string]interface{}) |
| if !ok || len(row) < 1 { |
| continue |
| } |
| |
| if idx == 0 { |
| if len(filter) > 0 { |
| header = filter |
| } else { |
| for rk := range row { |
| header = append(header, strings.ToUpper(rk)) |
| } |
| sort.Strings(header) |
| } |
| fmt.Fprintln(w, strings.Join(header, "\t")) |
| } |
| var values []string |
| for _, key := range header { |
| values = append(values, jsonify(row[strings.ToLower(key)], format)) |
| } |
| fmt.Fprintln(w, strings.Join(values, "\t")) |
| } |
| } |
| } |
| w.Flush() |
| } |
| |
| func printCsv(response map[string]interface{}, filter []string) { |
| format := "csv" |
| for _, v := range response { |
| valueType := reflect.TypeOf(v) |
| if valueType.Kind() == reflect.Slice || valueType.Kind() == reflect.Map { |
| items, ok := v.([]interface{}) |
| if !ok { |
| continue |
| } |
| var header []string |
| for idx, item := range items { |
| row, ok := item.(map[string]interface{}) |
| if !ok || len(row) < 1 { |
| continue |
| } |
| |
| if idx == 0 { |
| if len(filter) > 0 { |
| header = filter |
| } else { |
| for rk := range row { |
| header = append(header, rk) |
| } |
| sort.Strings(header) |
| } |
| fmt.Println(strings.Join(header, ",")) |
| } |
| var values []string |
| for _, key := range header { |
| values = append(values, jsonify(row[key], format)) |
| } |
| fmt.Println(strings.Join(values, ",")) |
| } |
| } |
| } |
| } |
| |
| func filterResponse(response map[string]interface{}, filter []string, outputType string) map[string]interface{} { |
| if filter == nil || len(filter) == 0 { |
| return response |
| } |
| filteredResponse := make(map[string]interface{}) |
| for k, v := range response { |
| valueType := reflect.TypeOf(v) |
| if valueType.Kind() == reflect.Slice || valueType.Kind() == reflect.Map { |
| items, ok := v.([]interface{}) |
| if !ok { |
| continue |
| } |
| var filteredRows []interface{} |
| for _, item := range items { |
| row, ok := item.(map[string]interface{}) |
| if !ok || len(row) < 1 { |
| continue |
| } |
| filteredRow := make(map[string]interface{}) |
| for _, filterKey := range filter { |
| for field := range row { |
| if filterKey == field { |
| filteredRow[field] = row[field] |
| } |
| } |
| if outputType == config.COLUMN || outputType == config.CSV || outputType == config.TABLE { |
| if _, ok := filteredRow[filterKey]; !ok { |
| filteredRow[filterKey] = "" |
| } |
| } |
| } |
| filteredRows = append(filteredRows, filteredRow) |
| } |
| filteredResponse[k] = filteredRows |
| } else { |
| filteredResponse[k] = v |
| continue |
| } |
| |
| } |
| return filteredResponse |
| } |
| |
| func printResult(outputType string, response map[string]interface{}, filter []string) { |
| response = filterResponse(response, filter, outputType) |
| switch outputType { |
| case config.JSON: |
| printJSON(response) |
| case config.TEXT: |
| printText(response) |
| case config.COLUMN: |
| printColumn(response, filter) |
| case config.CSV: |
| printCsv(response, filter) |
| case config.TABLE: |
| printTable(response, filter) |
| case config.DEFAULT: |
| printJSON(response) |
| default: |
| fmt.Println("Invalid output type configured, please fix that!") |
| } |
| } |