This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git
The following commit(s) were added to refs/heads/master by this push:
new 6a00de5 output: implement and refactor json, csv, table, text outputs
6a00de5 is described below
commit 6a00de565e42dd532890eff19888f351e7ac3c40
Author: Rohit Yadav <[email protected]>
AuthorDate: Tue Jun 26 16:41:26 2018 +0530
output: implement and refactor json, csv, table, text outputs
Signed-off-by: Rohit Yadav <[email protected]>
---
Makefile | 2 +-
NOTICE | 5 --
cmd/api.go | 88 --------------------------
cmd/command.go | 10 +--
cmd/output.go | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/version.go | 1 +
config/cache.go | 7 ++-
config/config.go | 5 +-
8 files changed, 201 insertions(+), 104 deletions(-)
diff --git a/Makefile b/Makefile
index 517c231..d19ba76 100644
--- a/Makefile
+++ b/Makefile
@@ -52,7 +52,7 @@ run: all
debug:
$(GO) build -gcflags='-N -l' -o cmk cmk.go && dlv --listen=:2345
--headless=true --api-version=2 exec ./cmk
-dist:
+dist: all
cd $(BASE)
rm -fr dist
mkdir -p dist
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index 2fcb349..0000000
--- a/NOTICE
+++ /dev/null
@@ -1,5 +0,0 @@
-Apache CloudStack CloudMonkey
-Copyright 2018 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
diff --git a/cmd/api.go b/cmd/api.go
index 1100f55..0c3b7fd 100644
--- a/cmd/api.go
+++ b/cmd/api.go
@@ -18,16 +18,9 @@
package cmd
import (
- "encoding/json"
"errors"
"fmt"
- "github.com/olekukonko/tablewriter"
- "os"
- "reflect"
- "sort"
"strings"
-
- "cmk/config"
)
var apiCommand *Command
@@ -37,87 +30,6 @@ func GetAPIHandler() *Command {
return apiCommand
}
-func printText(itemMap map[string]interface{}) {
- for k, v := range itemMap {
- valueType := reflect.TypeOf(v)
- if valueType.Kind() == reflect.Slice {
- fmt.Printf("%s:\n", k)
- for _, item := range v.([]interface{}) {
- row, isMap := item.(map[string]interface{})
- if isMap {
- for field, value := range row {
- fmt.Printf("%s = %v\n", field,
value)
- }
- } else {
- fmt.Printf("%v\n", item)
- }
-
fmt.Println("================================================================================")
- }
- } else {
- fmt.Printf("%s = %v\n", k, v)
- }
- }
-}
-
-func printResult(outputType string, response map[string]interface{}, filter
[]string) {
- switch outputType {
- case config.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("%s:\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 filter != nil && len(filter)
> 0 {
- for _, filterKey :=
range filter {
- for field :=
range row {
- if
filterKey == field {
-
header = append(header, field)
- }
- }
- }
- } 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,
fmt.Sprintf("%v", row[field]))
- }
- table.Append(rowArray)
- }
- } else {
- fmt.Printf("%s = %v\n", k, v)
- }
- }
- table.Render()
- case config.TEXT:
- case config.DEFAULT:
- printText(response)
- case config.CSV:
- fmt.Println("FIXME: implement CSV output")
- fmt.Println(response)
- default:
- jsonOutput, _ := json.MarshalIndent(response, "", " ")
- fmt.Println(string(jsonOutput))
- }
-}
-
func init() {
apiCommand = &Command{
Name: "api",
diff --git a/cmd/command.go b/cmd/command.go
index 7d5a2fe..179dd74 100644
--- a/cmd/command.go
+++ b/cmd/command.go
@@ -58,12 +58,12 @@ func PrintUsage() {
for _, cmd := range commands {
commandHelp += fmt.Sprintf("%s\t\t%s\n", cmd.Name, cmd.Help)
}
- fmt.Printf(`usage: cmk [options] [commands]
+ fmt.Printf(`Usage: cmk [options] [commands]
-Command Line Interface for Apache CloudStack
+CloudMonkey (cmk) 🐵 is a command line interface for Apache CloudStack.
-default commands:
+Default commands:
%s
-
-Try cmk [help]`, commandHelp)
+Try cmk [help] or cmk [action api] -h
+`, commandHelp)
}
diff --git a/cmd/output.go b/cmd/output.go
new file mode 100644
index 0000000..4a13286
--- /dev/null
+++ b/cmd/output.go
@@ -0,0 +1,187 @@
+// 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 (
+ "cmk/config"
+ "encoding/json"
+ "fmt"
+ "github.com/olekukonko/tablewriter"
+ "os"
+ "reflect"
+ "sort"
+ "strings"
+)
+
+func printJson(response map[string]interface{}) {
+ jsonOutput, err := json.MarshalIndent(response, "", " ")
+ if err != nil {
+ fmt.Println("Error during json marshalling:", err.Error())
+ }
+ fmt.Println(string(jsonOutput))
+}
+
+func printTable(response map[string]interface{}) {
+ 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("%s:\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 {
+ for field := range row {
+ header = append(header, field)
+ }
+ sort.Strings(header)
+ table.SetHeader(header)
+ }
+ var rowArray []string
+ for _, field := range header {
+ rowArray = append(rowArray,
fmt.Sprintf("%v", row[field]))
+ }
+ table.Append(rowArray)
+ }
+ } else {
+ fmt.Printf("%s = %v\n", k, v)
+ }
+ }
+ table.Render()
+}
+
+func printText(response map[string]interface{}) {
+ for k, v := range response {
+ valueType := reflect.TypeOf(v)
+ if valueType.Kind() == reflect.Slice {
+ fmt.Printf("%s:\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,
value)
+ }
+ } else {
+ fmt.Printf("%v\n", item)
+ }
+ }
+ } else {
+ fmt.Printf("%s = %v\n", k, v)
+ }
+ }
+}
+
+func printCsv(response map[string]interface{}) {
+ 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 {
+ 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,
fmt.Sprintf("%v", row[key]))
+ }
+ fmt.Println(strings.Join(values, ","))
+ }
+
+ }
+ }
+}
+
+func filterResponse(response map[string]interface{}, filter []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]
+ }
+ }
+ }
+ 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)
+ switch outputType {
+ case config.JSON:
+ printJson(response)
+ case config.TABLE:
+ printTable(response)
+ case config.TEXT:
+ printText(response)
+ case config.CSV:
+ printCsv(response)
+ case config.XML:
+ fmt.Println("Unfinished output format: xml, use something else")
+ default:
+ fmt.Println("Invalid output type configured, please fix that!")
+ }
+}
diff --git a/cmd/version.go b/cmd/version.go
index c07c1d7..09f48b8 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -25,6 +25,7 @@ func init() {
Help: "Version info",
Handle: func(r *Request) error {
fmt.Println(r.Config.Name(), r.Config.Version())
+ fmt.Println("Copyright 2018 The Apache Software
Foundation (http://www.apache.org/)")
return nil
},
})
diff --git a/config/cache.go b/config/cache.go
index 216cf02..2037ff7 100644
--- a/config/cache.go
+++ b/config/cache.go
@@ -82,7 +82,9 @@ func (c *Config) GetCache() map[string]*API {
func LoadCache(c *Config) {
cache, err := ioutil.ReadFile(c.CacheFile)
if err != nil {
- fmt.Fprintf(os.Stderr, "Loaded in-built API cache. Failed to
read API cache, please run 'sync'.\n")
+ if c.HasShell {
+ fmt.Fprintf(os.Stderr, "Loaded in-built API cache.
Failed to read API cache, please run 'sync'.\n")
+ }
cache = []byte(preCache)
}
var data map[string]interface{}
@@ -156,6 +158,9 @@ func (c *Config) UpdateCache(response
map[string]interface{}) interface{} {
var responseKeys []string
for _, respNode := range api["response"].([]interface{}) {
if resp, ok := respNode.(map[string]interface{}); ok {
+ if resp == nil || resp["name"] == nil {
+ continue
+ }
responseKeys = append(responseKeys,
fmt.Sprintf("%v,", resp["name"]))
}
}
diff --git a/config/config.go b/config/config.go
index 7d6fc09..ccbd23a 100644
--- a/config/config.go
+++ b/config/config.go
@@ -36,10 +36,7 @@ const (
JSON = "json"
TABLE = "table"
TEXT = "text"
-
- // Old formats existing for some backward compatibilities
- DEFAULT = "default" // This is same as 'text'
- XML = "xml"
+ XML = "xml"
)
// ServerProfile describes a management server