blob: b697da95e4c69ac1a9c41f28c5018adcf9c35656 [file] [log] [blame]
// 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!")
}
}