Set different default display style for different commands (#101)
* set default display and add command association
diff --git a/cmd/swctl/main.go b/cmd/swctl/main.go
index d430416..0a51e6d 100644
--- a/cmd/swctl/main.go
+++ b/cmd/swctl/main.go
@@ -106,7 +106,7 @@
Name: "display",
Required: false,
Usage: "display `style` of the result, supported styles are: json, yaml, table, graph",
- Value: "json",
+ Value: "",
}),
}
@@ -129,6 +129,7 @@
})
app.Flags = flags
+ app.CommandNotFound = util.CommandNotFound
if err := app.Run(os.Args); err != nil {
log.Fatalln(err)
diff --git a/pkg/display/display.go b/pkg/display/display.go
index 9dd17b8..455cfb9 100644
--- a/pkg/display/display.go
+++ b/pkg/display/display.go
@@ -19,6 +19,7 @@
import (
"fmt"
+
"strings"
d "github.com/apache/skywalking-cli/pkg/display/displayable"
@@ -39,10 +40,30 @@
GRAPH = "graph"
)
+// The variable style sets the output style for the command.
+var style = map[string]string{"dashboard global": "graph",
+ "dashboard global-metrics": "graph",
+ "metrics top": "table",
+ "metrics linear": "graph",
+ "metrics list": "table",
+ "service list": "table",
+ "t": "graph",
+ "trace": "graph"}
+
// Display the object in the style specified in flag --display
func Display(ctx *cli.Context, displayable *d.Displayable) error {
displayStyle := ctx.GlobalString("display")
-
+ if displayStyle == "" {
+ commandFullName := ctx.Command.FullName()
+ if commandFullName != "" {
+ displayStyle = getDisplayStyle(commandFullName)
+ } else if ctx.Parent() != nil {
+ displayStyle = getDisplayStyle(ctx.Parent().Args()[0])
+ }
+ }
+ if displayStyle == "" {
+ displayStyle = "json"
+ }
switch strings.ToLower(displayStyle) {
case JSON:
return json.Display(displayable)
@@ -56,3 +77,11 @@
return fmt.Errorf("unsupported display style: %s", displayStyle)
}
}
+
+// getDisplayStyle gets the default display settings.
+func getDisplayStyle(fullName string) string {
+ if command, ok := style[fullName]; ok {
+ return command
+ }
+ return ""
+}
diff --git a/pkg/util/commandNotFound.go b/pkg/util/commandNotFound.go
new file mode 100644
index 0000000..b310cdb
--- /dev/null
+++ b/pkg/util/commandNotFound.go
@@ -0,0 +1,94 @@
+// Licensed to 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. Apache Software Foundation (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 util
+
+import (
+ "fmt"
+
+ "github.com/urfave/cli"
+)
+
+const GAP = 3 // Control the appropriate edit distance.
+
+// CommandNotFound is executed when the command entered does not exist.
+func CommandNotFound(c *cli.Context, s string) {
+ suppose := make([]string, 0)
+ var parentCommand string
+ if c.Parent() == nil {
+ parentCommand = "swctl"
+ } else {
+ parentCommand = c.Parent().Args()[0]
+ }
+ fmt.Printf("Error: unknown command \"%s\" for \"%s\" \n\n", s, parentCommand)
+ // Record commands whose edit distance is less than GAP to suppose.
+ for index := range c.App.Commands {
+ commandName := c.App.Commands[index].Name
+ distance := minEditDistance(commandName, s)
+ if distance <= GAP && commandName != "help" {
+ suppose = append(suppose, commandName)
+ }
+ }
+ if len(suppose) != 0 {
+ fmt.Println("Do you mean this?")
+ for index := range suppose {
+ fmt.Printf("\t%s\n", suppose[index])
+ }
+ fmt.Println()
+ }
+ if c.Parent() == nil {
+ fmt.Printf("Run '%s --help' for usage.\n", parentCommand)
+ } else {
+ fmt.Printf("Run 'swctl %s --help' for usage.\n", parentCommand)
+ }
+}
+
+// minEditDistance calculates the edit distance of two strings.
+func minEditDistance(word1, word2 string) int {
+ m, n := len(word1), len(word2)
+ dp := make([][]int, m+1)
+ for i := range dp {
+ dp[i] = make([]int, n+1)
+ }
+ for i := 0; i < m+1; i++ {
+ dp[i][0] = i
+ }
+ for j := 0; j < n+1; j++ {
+ dp[0][j] = j
+ }
+ for i := 1; i < m+1; i++ {
+ for j := 1; j < n+1; j++ {
+ if word1[i-1] == word2[j-1] {
+ dp[i][j] = dp[i-1][j-1]
+ } else {
+ dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
+ }
+ }
+ }
+ return dp[m][n]
+}
+
+// min get The minimum of the args.
+func min(args ...int) int {
+ min := args[0]
+ for _, item := range args {
+ if item < min {
+ min = item
+ }
+ }
+ return min
+}
diff --git a/pkg/util/commandNotFound_test.go b/pkg/util/commandNotFound_test.go
new file mode 100644
index 0000000..8f23df8
--- /dev/null
+++ b/pkg/util/commandNotFound_test.go
@@ -0,0 +1,57 @@
+// Licensed to 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. Apache Software Foundation (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 util
+
+import "testing"
+
+func Test_minEditDistance(t *testing.T) {
+ type args struct {
+ word1 string
+ word2 string
+ }
+ tests := []struct {
+ name string
+ args args
+ want int
+ }{
+ {
+ name: "empty strings",
+ args: args{"", ""},
+ want: 0,
+ }, {
+ name: "one empty string",
+ args: args{"", "dashboard"},
+ want: 9,
+ }, {
+ name: "equal length",
+ args: args{"service", "service"},
+ want: 0,
+ }, {
+ name: "unequal length",
+ args: args{"even", "event"},
+ want: 1,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := minEditDistance(tt.args.word1, tt.args.word2); got != tt.want {
+ t.Errorf("minDistance() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}