openwhisk-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From csantan...@apache.org
Subject [incubator-openwhisk-cli] 03/10: Allow CLI to sort entities by name (#2326)
Date Thu, 17 Aug 2017 17:17:44 GMT
This is an automated email from the ASF dual-hosted git repository.

csantanapr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-cli.git

commit 6aae54c1beb3b77cbfadb6783d5e67b11ce07b91
Author: Brandon Lee Underwood <Brandon.Lee.Underwood@ibm.com>
AuthorDate: Thu Aug 10 21:47:07 2017 -0400

    Allow CLI to sort entities by name (#2326)
    
    - Created interfaces `Printables` and `Sortables`
    - Made Actions, Triggers, Packages, Rules, APIs into Printables and Sortables
    - Made Activations into Printables and Sortables, Sort currently undefined
    - Made alphabetic sorting default, sort by last update time with --time flag
    - Changed sorting default back to last update time, --sort flag for alphabetical sorting
    - Updated flag name to "--name-sort"/"-n"
    - Updated Docs
    - Fixed rule status printing for `wsk list` and `wsk namespace get`
---
 commands/action.go               |   4 +-
 commands/activation.go           |   2 +-
 commands/api.go                  | 120 ++++++++++++++++++-----------
 commands/flags.go                |   1 +
 commands/namespace.go            |  25 ++++--
 commands/package.go              |   5 +-
 commands/rule.go                 |   5 +-
 commands/trigger.go              |   4 +-
 commands/util.go                 | 162 ++++++++++++++++++++++-----------------
 commands/wsk.go                  |   2 +
 wski18n/i18n_resources.go        |  22 +++---
 wski18n/resources/en_US.all.json |  19 +++--
 12 files changed, 230 insertions(+), 141 deletions(-)

diff --git a/commands/action.go b/commands/action.go
index 83e89fa..f14cc9a 100644
--- a/commands/action.go
+++ b/commands/action.go
@@ -321,7 +321,8 @@ var actionListCmd = &cobra.Command{
             return actionListError(qualifiedName.GetEntityName(), options, err)
         }
 
-        printList(actions)
+        sortByName := flags.common.nameSort
+        printList(actions, sortByName)
 
         return nil
     },
@@ -942,6 +943,7 @@ func init() {
 
     actionListCmd.Flags().IntVarP(&Flags.common.skip, "skip", "s", 0, wski18n.T("exclude
the first `SKIP` number of actions from the result"))
     actionListCmd.Flags().IntVarP(&Flags.common.limit, "limit", "l", 30, wski18n.T("only
return `LIMIT` number of actions from the collection"))
+    actionListCmd.Flags().BoolVarP(&Flags.common.nameSort, "name-sort", "n", false, wski18n.T("sorts
a list alphabetically by entity name; only applicable within the limit/skip returned entity
block"))
 
     actionCmd.AddCommand(
         actionCreateCmd,
diff --git a/commands/activation.go b/commands/activation.go
index 8273351..29f8f48 100644
--- a/commands/activation.go
+++ b/commands/activation.go
@@ -93,7 +93,7 @@ var activationListCmd = &cobra.Command{
         if options.Docs == true {
             printFullActivationList(activations)
         } else {
-            printList(activations)
+            printList(activations, false)   // Default sorting for Activations are by creation
time, hence sortByName is always false
         }
 
         return nil
diff --git a/commands/api.go b/commands/api.go
index cec47eb..0f7f01c 100644
--- a/commands/api.go
+++ b/commands/api.go
@@ -93,7 +93,6 @@ func isValidRelpath(relpath string) (error, bool) {
     return nil, true
 }
 
-
 /*
  * Pull the managedUrl (external API URL) from the API configuration
  */
@@ -445,6 +444,8 @@ var apiListCmd = &cobra.Command{
         var retApiArray *whisk.RetApiArray
         var apiPath string
         var apiVerb string
+        var orderFilteredList []whisk.ApiFilteredList
+        var orderFilteredRow []whisk.ApiFilteredRow
 
         if whiskErr := checkArgs(args, 0, 3, "Api list",
             wski18n.T("Optional parameters are: API base path (or API name), API relative
path and operation.")); whiskErr != nil {
@@ -518,7 +519,8 @@ var apiListCmd = &cobra.Command{
             // Cast to a common type to allow for code to print out apilist response or apiget
response
             retApiArray = (*whisk.RetApiArray)(retApi)
         }
-
+        //Checks for any order flags being passed
+        sortByName := flags.common.nameSort
         // Display the APIs - applying any specified filtering
         if (Flags.common.full) {
             fmt.Fprintf(color.Output,
@@ -526,10 +528,10 @@ var apiListCmd = &cobra.Command{
                     map[string]interface{}{
                         "ok": color.GreenString("ok:"),
                     }))
-
-            for i:=0; i<len(retApiArray.Apis); i++ {
-                printFilteredListApi(retApiArray.Apis[i].ApiValue, apiPath, apiVerb)
+            for i := 0; i < len(retApiArray.Apis); i++ {
+                orderFilteredList = append(orderFilteredList, genFilteredList(retApiArray.Apis[i].ApiValue,
apiPath, apiVerb)...)
             }
+            printList(orderFilteredList, sortByName)  // Sends an array of structs that contains
specifed variables that are not truncated
         } else {
             if (len(retApiArray.Apis) > 0) {
                 // Dynamically create the output format string based on the maximum size
of the
@@ -542,17 +544,17 @@ var apiListCmd = &cobra.Command{
                         map[string]interface{}{
                             "ok": color.GreenString("ok:"),
                         }))
-                fmt.Printf(fmtString, "Action", "Verb", "API Name", "URL")
-                for i:=0; i<len(retApiArray.Apis); i++ {
-                    printFilteredListRow(retApiArray.Apis[i].ApiValue, apiPath, apiVerb,
maxActionNameSize, maxApiNameSize)
+                for i := 0; i < len(retApiArray.Apis); i++ {
+                    orderFilteredRow = append(orderFilteredRow, genFilteredRow(retApiArray.Apis[i].ApiValue,
apiPath, apiVerb, maxActionNameSize, maxApiNameSize)...)
                 }
+                printList(orderFilteredRow, sortByName)  // Sends an array of structs that
contains specifed variables that are truncated
             } else {
                 fmt.Fprintf(color.Output,
                     wski18n.T("{{.ok}} APIs\n",
                         map[string]interface{}{
                             "ok": color.GreenString("ok:"),
                         }))
-                fmt.Printf(fmtString, "Action", "Verb", "API Name", "URL")
+                printList(orderFilteredRow, sortByName)  // Sends empty orderFilteredRow
so that defaultHeader can be printed
             }
         }
 
@@ -560,24 +562,25 @@ var apiListCmd = &cobra.Command{
     },
 }
 
-/*
- * Takes an API object (containing one more more single basepath/relpath/operation triplets)
- * and some filtering configuration.  For each API endpoint matching the filtering criteria,
display
- * each endpoint's configuration - one line per configuration property (action name, verb,
api name, api gw url)
- */
-func printFilteredListApi(resultApi *whisk.RetApi, apiPath string, apiVerb string) {
+// genFilteredList(resultApi, api) generates an array of
+//      ApiFilteredLists for the purpose of ordering and printing in a list form.
+//      NOTE: genFilteredRow() generates entries with one line per configuration
+//         property (action name, verb, api name, api gw url)
+func genFilteredList(resultApi *whisk.RetApi, apiPath string, apiVerb string) []whisk.ApiFilteredList{
+    var orderInfo whisk.ApiFilteredList
+    var orderInfoArr []whisk.ApiFilteredList
     baseUrl := strings.TrimSuffix(resultApi.BaseUrl, "/")
     apiName := resultApi.Swagger.Info.Title
     basePath := resultApi.Swagger.BasePath
     if (resultApi.Swagger != nil && resultApi.Swagger.Paths != nil) {
         for path, _ := range resultApi.Swagger.Paths {
-            whisk.Debug(whisk.DbgInfo, "printFilteredListApi: comparing api relpath: %s\n",
path)
+            whisk.Debug(whisk.DbgInfo, "genFilteredList: comparing api relpath: %s\n", path)
             if ( len(apiPath) == 0 || path == apiPath) {
-                whisk.Debug(whisk.DbgInfo, "printFilteredListApi: relpath matches\n")
+                whisk.Debug(whisk.DbgInfo, "genFilteredList: relpath matches\n")
                 for op, opv  := range resultApi.Swagger.Paths[path] {
-                    whisk.Debug(whisk.DbgInfo, "printFilteredListApi: comparing operation:
'%s'\n", op)
+                    whisk.Debug(whisk.DbgInfo, "genFilteredList: comparing operation: '%s'\n",
op)
                     if ( len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb))
{
-                        whisk.Debug(whisk.DbgInfo, "printFilteredListApi: operation matches:
%#v\n", opv)
+                        whisk.Debug(whisk.DbgInfo, "genFilteredList: operation matches: %#v\n",
opv)
                         var actionName string
                         if (opv.XOpenWhisk == nil) {
                             actionName = ""
@@ -586,38 +589,36 @@ func printFilteredListApi(resultApi *whisk.RetApi, apiPath string, apiVerb
strin
                         } else {
                             actionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.ActionName
                         }
-                        fmt.Printf("%s: %s\n", wski18n.T("Action"), actionName)
-                        fmt.Printf("  %s: %s\n", wski18n.T("API Name"), apiName)
-                        fmt.Printf("  %s: %s\n", wski18n.T("Base path"), basePath)
-                        fmt.Printf("  %s: %s\n", wski18n.T("Path"), path)
-                        fmt.Printf("  %s: %s\n", wski18n.T("Verb"), op)
-                        fmt.Printf("  %s: %s\n", wski18n.T("URL"), baseUrl+path)
+                        orderInfo = AssignListInfo(actionName, op, apiName, basePath, path,
baseUrl+path)
+                        whisk.Debug(whisk.DbgInfo, "Appening to orderInfoArr: %s %s\n", orderInfo.RelPath)
+                        orderInfoArr = append(orderInfoArr, orderInfo)
                     }
                 }
             }
         }
     }
+    return orderInfoArr
 }
 
-/*
- * Takes an API object (containing one more more single basepath/relpath/operation triplets)
- * and some filtering configuration.  For each API matching the filtering criteria, display
the API
- * on a single line (action name, verb, api name, api gw url).
- *
- * NOTE: Large action name and api name value will be truncated by their associated max size
parameters.
- */
-func printFilteredListRow(resultApi *whisk.RetApi, apiPath string, apiVerb string, maxActionNameSize
int, maxApiNameSize int) {
+// genFilteredRow(resultApi, api, maxApiNameSize, maxApiNameSize) generates an array of
+//      ApiFilteredRows for the purpose of ordering and printing in a list form by parsing
and
+//      initializing vaules for each individual ApiFilteredRow struct.
+//      NOTE: Large action and api name values will be truncated by their associated max
size parameters.
+func genFilteredRow(resultApi *whisk.RetApi, apiPath string, apiVerb string, maxActionNameSize
int, maxApiNameSize int) []whisk.ApiFilteredRow {
+    var orderInfo whisk.ApiFilteredRow
+    var orderInfoArr []whisk.ApiFilteredRow
     baseUrl := strings.TrimSuffix(resultApi.BaseUrl, "/")
     apiName := resultApi.Swagger.Info.Title
+    basePath := resultApi.Swagger.BasePath
     if (resultApi.Swagger != nil && resultApi.Swagger.Paths != nil) {
         for path, _ := range resultApi.Swagger.Paths {
-            whisk.Debug(whisk.DbgInfo, "printFilteredListRow: comparing api relpath: %s\n",
path)
+            whisk.Debug(whisk.DbgInfo, "genFilteredRow: comparing api relpath: %s\n", path)
             if ( len(apiPath) == 0 || path == apiPath) {
-                whisk.Debug(whisk.DbgInfo, "printFilteredListRow: relpath matches\n")
+                whisk.Debug(whisk.DbgInfo, "genFilteredRow: relpath matches\n")
                 for op, opv  := range resultApi.Swagger.Paths[path] {
-                    whisk.Debug(whisk.DbgInfo, "printFilteredListRow: comparing operation:
'%s'\n", op)
+                    whisk.Debug(whisk.DbgInfo, "genFilteredRow: comparing operation: '%s'\n",
op)
                     if ( len(apiVerb) == 0 || strings.ToLower(op) == strings.ToLower(apiVerb))
{
-                        whisk.Debug(whisk.DbgInfo, "printFilteredListRow: operation matches:
%#v\n", opv)
+                        whisk.Debug(whisk.DbgInfo, "genFilteredRow: operation matches: %#v\n",
opv)
                         var actionName string
                         if (opv.XOpenWhisk == nil) {
                             actionName = ""
@@ -626,21 +627,51 @@ func printFilteredListRow(resultApi *whisk.RetApi, apiPath string, apiVerb
strin
                         } else {
                             actionName = "/"+opv.XOpenWhisk.Namespace+"/"+opv.XOpenWhisk.ActionName
                         }
-                        fmt.Printf(fmtString,
-                            actionName[0 : min(len(actionName), maxActionNameSize)],
-                            op,
-                            apiName[0 : min(len(apiName), maxApiNameSize)],
-                            baseUrl+path)
+                        orderInfo = AssignRowInfo(actionName[0 : min(len(actionName), maxActionNameSize)],
op, apiName[0 : min(len(apiName), maxApiNameSize)], basePath, path, baseUrl+path)
+                        orderInfo.FmtString = fmtString
+                        whisk.Debug(whisk.DbgInfo, "Appening to orderInfoArr: %s %s\n", orderInfo.RelPath)
+                        orderInfoArr = append(orderInfoArr, orderInfo)
                     }
                 }
             }
         }
     }
+    return orderInfoArr
+}
+
+// AssignRowInfo(actionName, verb, apiName, basePath, relPath, url) assigns
+//      the given vaules to and initializes an ApiFilteredRow struct, then returns it.
+func AssignRowInfo(actionName string, verb string, apiName string, basePath string, relPath
string, url string) whisk.ApiFilteredRow {
+    var orderInfo whisk.ApiFilteredRow
+
+    orderInfo.ActionName = actionName
+    orderInfo.Verb = verb
+    orderInfo.ApiName = apiName
+    orderInfo.BasePath = basePath
+    orderInfo.RelPath = relPath
+    orderInfo.Url = url
+
+    return orderInfo
+}
+
+// AssignListInfo(actionName, verb, apiName, basePath, relPath, url) assigns
+//      the given vaules to and initializes an ApiFilteredList struct, then returns it.
+func AssignListInfo(actionName string, verb string, apiName string, basePath string, relPath
string, url string) whisk.ApiFilteredList {
+    var orderInfo whisk.ApiFilteredList
+
+    orderInfo.ActionName = actionName
+    orderInfo.Verb = verb
+    orderInfo.ApiName = apiName
+    orderInfo.BasePath = basePath
+    orderInfo.RelPath = relPath
+    orderInfo.Url = url
+
+    return orderInfo
 }
 
 func getLargestActionNameSize(retApiArray *whisk.RetApiArray, apiPath string, apiVerb string)
int {
     var maxNameSize = 0
-    for i:=0; i<len(retApiArray.Apis); i++ {
+    for i := 0; i < len(retApiArray.Apis); i++ {
         var resultApi = retApiArray.Apis[i].ApiValue
         if (resultApi.Swagger != nil && resultApi.Swagger.Paths != nil) {
             for path, _ := range resultApi.Swagger.Paths {
@@ -673,7 +704,7 @@ func getLargestActionNameSize(retApiArray *whisk.RetApiArray, apiPath
string, ap
 
 func getLargestApiNameSize(retApiArray *whisk.RetApiArray, apiPath string, apiVerb string)
int {
     var maxNameSize = 0
-    for i:=0; i<len(retApiArray.Apis); i++ {
+    for i := 0; i < len(retApiArray.Apis); i++ {
         var resultApi = retApiArray.Apis[i].ApiValue
         apiName := resultApi.Swagger.Info.Title
         if (resultApi.Swagger != nil && resultApi.Swagger.Paths != nil) {
@@ -920,6 +951,7 @@ func init() {
     apiGetCmd.Flags().StringVarP(&Flags.common.format, "format", "", formatOptionJson,
wski18n.T("Specify the API output `TYPE`, either json or yaml"))
     apiListCmd.Flags().IntVarP(&Flags.common.skip, "skip", "s", 0, wski18n.T("exclude
the first `SKIP` number of actions from the result"))
     apiListCmd.Flags().IntVarP(&Flags.common.limit, "limit", "l", 30, wski18n.T("only
return `LIMIT` number of actions from the collection"))
+    apiListCmd.Flags().BoolVarP(&Flags.common.nameSort, "name-sort", "n", false, wski18n.T("sorts
a list alphabetically by order of [BASE_PATH | API_NAME], API_PATH, then API_VERB; only applicable
within the limit/skip returned entity block"))
     apiListCmd.Flags().BoolVarP(&Flags.common.full, "full", "f", false, wski18n.T("display
full description of each API"))
     apiCmd.AddCommand(
         apiCreateCmd,
diff --git a/commands/flags.go b/commands/flags.go
index 7ef23d6..9a3454f 100644
--- a/commands/flags.go
+++ b/commands/flags.go
@@ -61,6 +61,7 @@ type FlagsStruct struct {
         feed        string  // name of feed
         detail      bool
         format      string
+        nameSort   bool    // sorts list alphabetically by entity name
     }
 
     property struct {
diff --git a/commands/namespace.go b/commands/namespace.go
index a9f7bef..f7af0fc 100644
--- a/commands/namespace.go
+++ b/commands/namespace.go
@@ -55,7 +55,7 @@ var namespaceListCmd = &cobra.Command{
             werr := whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_NETWORK,
whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE)
             return werr
         }
-        printList(namespaces)
+        printList(namespaces, false) // `-n` flag applies to `namespace get`, not list, so
must pass value false for printList here
         return nil
     },
 }
@@ -99,16 +99,31 @@ var namespaceGetCmd = &cobra.Command{
 
         fmt.Fprintf(color.Output, wski18n.T("Entities in namespace: {{.namespace}}\n",
             map[string]interface{}{"namespace": boldString(getClientNamespace())}))
-        printList(namespace.Contents.Packages)
-        printList(namespace.Contents.Actions)
-        printList(namespace.Contents.Triggers)
-        printList(namespace.Contents.Rules)
+        sortByName := flags.common.nameSort
+        printList(namespace.Contents.Packages, sortByName)
+        printList(namespace.Contents.Actions, sortByName)
+        printList(namespace.Contents.Triggers, sortByName)
+        //No errors, lets attempt to retrieve the status of each rule #312
+        for index, rule := range namespace.Contents.Rules {
+            ruleStatus, _, err := client.Rules.Get(rule.Name)
+            if err != nil {
+                errStr := wski18n.T("Unable to get status of rule '{{.name}}': {{.err}}",
+                    map[string]interface{}{"name": rule.Name, "err": err})
+                fmt.Println(errStr)
+                werr := whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_GENERAL,
whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE)
+                return werr
+            }
+            namespace.Contents.Rules[index].Status = ruleStatus.Status
+        }
+        printList(namespace.Contents.Rules, sortByName)
 
         return nil
     },
 }
 
 func init() {
+    namespaceGetCmd.Flags().BoolVarP(&flags.common.nameSort, "name-sort", "n", false,
wski18n.T("sorts a list alphabetically by entity name; only applicable within the limit/skip
returned entity block"))
+
     namespaceCmd.AddCommand(
         namespaceListCmd,
         namespaceGetCmd,
diff --git a/commands/package.go b/commands/package.go
index fcf6652..9dff500 100644
--- a/commands/package.go
+++ b/commands/package.go
@@ -412,7 +412,8 @@ var packageListCmd = &cobra.Command{
       return werr
     }
 
-    printList(packages)
+    sortByName := flags.common.nameSort
+    printList(packages, sortByName)
 
     return nil
   },
@@ -503,6 +504,7 @@ var packageRefreshCmd = &cobra.Command{
 }
 
 func init() {
+<<<<<<< HEAD
   packageCreateCmd.Flags().StringSliceVarP(&Flags.common.annotation, "annotation", "a",
[]string{}, wski18n.T("annotation values in `KEY VALUE` format"))
   packageCreateCmd.Flags().StringVarP(&Flags.common.annotFile, "annotation-file", "A",
"", wski18n.T("`FILE` containing annotation values in JSON format"))
   packageCreateCmd.Flags().StringSliceVarP(&Flags.common.param, "param", "p", []string{},
wski18n.T("parameter values in `KEY VALUE` format"))
@@ -524,6 +526,7 @@ func init() {
 
   packageListCmd.Flags().IntVarP(&Flags.common.skip, "skip", "s", 0, wski18n.T("exclude
the first `SKIP` number of packages from the result"))
   packageListCmd.Flags().IntVarP(&Flags.common.limit, "limit", "l", 30, wski18n.T("only
return `LIMIT` number of packages from the collection"))
+  packageListCmd.Flags().BoolVarP(&Flags.common.nameSort, "name-sort", "n", false, wski18n.T("sorts
a list alphabetically by entity name; only applicable within the limit/skip returned entity
block"))
 
   packageCmd.AddCommand(
     packageBindCmd,
diff --git a/commands/rule.go b/commands/rule.go
index 4d34af6..67cddf0 100644
--- a/commands/rule.go
+++ b/commands/rule.go
@@ -402,7 +402,9 @@ var ruleListCmd = &cobra.Command{
                 rules[index].Status = ruleStatus.Status
             }
         }
-        printList(rules)
+
+        sortByName := flags.common.nameSort
+        printList(rules, sortByName)
         return nil
     },
 }
@@ -414,6 +416,7 @@ func init() {
 
     ruleListCmd.Flags().IntVarP(&Flags.common.skip, "skip", "s", 0, wski18n.T("exclude
the first `SKIP` number of rules from the result"))
     ruleListCmd.Flags().IntVarP(&Flags.common.limit, "limit", "l", 30, wski18n.T("only
return `LIMIT` number of rules from the collection"))
+    ruleListCmd.Flags().BoolVarP(&Flags.common.nameSort, "name-sort", "n", false, wski18n.T("sorts
a list alphabetically by entity name; only applicable within the limit/skip returned entity
block"))
 
     ruleCmd.AddCommand(
         ruleCreateCmd,
diff --git a/commands/trigger.go b/commands/trigger.go
index 4b1c2e9..0d85af7 100644
--- a/commands/trigger.go
+++ b/commands/trigger.go
@@ -457,7 +457,8 @@ var triggerListCmd = &cobra.Command{
             werr := whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_GENERAL,
whisk.DISPLAY_MSG, whisk.NO_DISPLAY_USAGE)
             return werr
         }
-        printList(triggers)
+        sortByName := flags.common.nameSort
+        printList(triggers, sortByName)
         return nil
     },
 }
@@ -510,6 +511,7 @@ func init() {
 
     triggerListCmd.Flags().IntVarP(&Flags.common.skip, "skip", "s", 0, wski18n.T("exclude
the first `SKIP` number of triggers from the result"))
     triggerListCmd.Flags().IntVarP(&Flags.common.limit, "limit", "l", 30, wski18n.T("only
return `LIMIT` number of triggers from the collection"))
+    triggerListCmd.Flags().BoolVarP(&Flags.common.nameSort, "name-sort", "n", false,
wski18n.T("sorts a list alphabetically by entity name; only applicable within the limit/skip
returned entity block"))
 
     triggerCmd.AddCommand(
         triggerFireCmd,
diff --git a/commands/util.go b/commands/util.go
index 8bb5aae..de0b1f7 100644
--- a/commands/util.go
+++ b/commands/util.go
@@ -122,28 +122,99 @@ func getEscapedJSON(value string) (string) {
 func isValidJSON(value string) (bool) {
     var jsonInterface interface{}
     err := json.Unmarshal([]byte(value), &jsonInterface)
+
     return err == nil
 }
 
 var boldString = color.New(color.Bold).SprintFunc()
 
-func printList(collection interface{}) {
-    switch collection := collection.(type) {
+type Sortables []whisk.Sortable
+// Uses quickSort to sort commands based on their compare methods
+// Param: Takes in a array of Sortable interfaces which contains a specific command
+func Swap(sortables Sortables, i, j int) { sortables[i], sortables[j] = sortables[j], sortables[i]
}
+
+func toPrintable(sortable []whisk.Sortable) []whisk.Printable{
+    sortedPrintable := make([]whisk.Printable, len(sortable), len(sortable))
+    for i := range sortable {
+        sortedPrintable[i] = sortable[i].(whisk.Printable)
+    }
+    return sortedPrintable
+}
+
+// Prints the parameters/list for wsk xxxx list
+// Identifies type and then copies array into an array of interfaces(Sortable) to be sorted
and printed
+// Param: Takes in an interace which contains an array of a command(Ex: []Action)
+func printList(collection interface{}, sortByName bool) {
+    var commandToSort []whisk.Sortable
+    switch collection := collection.(type){
     case []whisk.Action:
-        printActionList(collection)
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
     case []whisk.Trigger:
-        printTriggerList(collection)
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
     case []whisk.Package:
-        printPackageList(collection)
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
     case []whisk.Rule:
-        printRuleList(collection)
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
     case []whisk.Namespace:
-        printNamespaceList(collection)
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
     case []whisk.Activation:
-        printActivationList(collection)
-    case []whisk.Api:
-        printApiList(collection)
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
+    case []whisk.ApiFilteredList:
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
+    case []whisk.ApiFilteredRow:
+        for i := range collection {
+            commandToSort = append(commandToSort, collection[i])
+        }
+    }
+    if sortByName && len(commandToSort) > 0 {
+        quickSort(commandToSort, 0, len(commandToSort)-1)
     }
+    printCommandsList(toPrintable(commandToSort), makeDefaultHeader(collection))
+}
+
+func quickSort(toSort Sortables, left int, right int) {
+    low := left
+    high := right
+    pivot := toSort[(left + right) / 2]
+
+    for low <= high {
+        for toSort[low].Compare(pivot) { low++ }
+        for pivot.Compare(toSort[high]) { high-- }
+        if low <= high {
+            Swap(toSort, low, high)
+            low++
+            high--
+        }
+    }
+    if left < high { quickSort(toSort, left, high) }
+    if low < right { quickSort(toSort, low, right) }
+}
+
+// makeDefaultHeader(collection) returns the default header to be used in case
+//      the list to be printed is empty.
+func makeDefaultHeader(collection interface{}) string {
+    defaultHeader := reflect.TypeOf(collection).String()
+    defaultHeader = strings.ToLower(defaultHeader[8:] + "s")    // Removes '[]whisk.' from
`[]whisk.ENTITY_TYPE`
+    if defaultHeader == "apifilteredrows" {
+        defaultHeader = fmt.Sprintf("%-30s %7s %20s  %s", "Action", "Verb", "API Name", "URL")
+    } else if defaultHeader == "apifilteredlists" {
+        defaultHeader = ""
+    }
+    return defaultHeader
 }
 
 func printFullList(collection interface{}) {
@@ -179,53 +250,18 @@ func printSummary(collection interface{}) {
     }
 }
 
-func printActionList(actions []whisk.Action) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("actions"))
-    for _, action := range actions {
-        publishState := wski18n.T("private")
-        kind := getValueString(action.Annotations, "exec")
-        fmt.Printf("%-70s %s %s\n", fmt.Sprintf("/%s/%s", action.Namespace, action.Name),
publishState, kind)
-    }
-}
-
-func printTriggerList(triggers []whisk.Trigger) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("triggers"))
-    for _, trigger := range triggers {
-        publishState := wski18n.T("private")
-        fmt.Printf("%-70s %s\n", fmt.Sprintf("/%s/%s", trigger.Namespace, trigger.Name),
publishState)
-    }
-}
-
-func printPackageList(packages []whisk.Package) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("packages"))
-    for _, xPackage := range packages {
-        publishState := wski18n.T("private")
-        if xPackage.Publish != nil && *xPackage.Publish {
-            publishState = wski18n.T("shared")
+// Used to print Action, Tigger, Package, and Rule lists
+// Param: Takes in a array of Printable interface, and the name of the command
+//          being sent to it
+// **Note**: The name sould be an empty string for APIs.
+func printCommandsList(commands []whisk.Printable, defaultHeader string) {
+    if len(commands) != 0 {
+        fmt.Fprint(color.Output, boldString(commands[0].ToHeaderString()))
+        for i := range commands {
+            fmt.Print(commands[i].ToSummaryRowString())
         }
-        fmt.Printf("%-70s %s\n", fmt.Sprintf("/%s/%s", xPackage.Namespace, xPackage.Name),
publishState)
-    }
-}
-
-func printRuleList(rules []whisk.Rule) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("rules"))
-    for _, rule := range rules {
-        publishState := wski18n.T("private")
-        fmt.Printf("%-70s %-20s %s\n", fmt.Sprintf("/%s/%s", rule.Namespace, rule.Name),
publishState, rule.Status)
-    }
-}
-
-func printNamespaceList(namespaces []whisk.Namespace) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("namespaces"))
-    for _, namespace := range namespaces {
-        fmt.Printf("%s\n", namespace.Name)
-    }
-}
-
-func printActivationList(activations []whisk.Activation) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("activations"))
-    for _, activation := range activations {
-        fmt.Printf("%s %-20s\n", activation.ActivationID, activation.Name)
+    } else {
+        fmt.Fprintf(color.Output, "%s\n", boldString(defaultHeader))
     }
 }
 
@@ -236,20 +272,6 @@ func printFullActivationList(activations []whisk.Activation) {
     }
 }
 
-func printApiList(apis []whisk.Api) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("apis"))
-    for _, api := range apis {
-        fmt.Printf("%s %20s %20s\n", api.ApiName, api.GatewayBasePath, api.GatewayFullPath)
-    }
-}
-
-func printFullApiList(apis []whisk.Api) {
-    fmt.Fprintf(color.Output, "%s\n", boldString("apis"))
-    for _, api := range apis {
-        printJSON(api)
-    }
-}
-
 func printActivationLogs(logs []string) {
     for _, log := range logs {
         fmt.Printf("%s\n", log)
diff --git a/commands/wsk.go b/commands/wsk.go
index f7f209b..874e549 100644
--- a/commands/wsk.go
+++ b/commands/wsk.go
@@ -44,6 +44,8 @@ func init() {
     WskCmd.SetHelpTemplate(`{{with or .Long .Short }}{{.}}
 {{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`)
 
+listCmd.Flags().BoolVarP(&flags.common.nameSort, "name-sort", "n", false, wski18n.T("sorts
a list alphabetically by entity name; only applicable within the limit/skip returned entity
block"))
+
     WskCmd.AddCommand(
         actionCmd,
         activationCmd,
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index 0042ed4..0d90c6a 100644
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -109,12 +109,12 @@ func wski18nResourcesDe_deAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/de_DE.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/de_DE.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
 
-var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x5d\x5f\x73\xdb\x38\x92\x7f\xcf\xa7\xe8\x9a\x17\x3b\x55\xb2\xb3\xfb\x74\x75\x99\x9a\x07\x4d\xec\xd9\x78\x93\xd8\xae\xc8\x99\xdd\xa9\x9b\xab\x11\x4c\x42\x12\xc6\x14\xc0\x01\x40\x2b\x4a\xd6\xdf\xfd\x0a\x00\x49\x91\x12\xfe\x92\x72\x72\x4f\x71\xc4\xee\x5f\x37\x80\x06\xd0\x68\x34\x80\xff\x79\x01\xf0\xf5\x05\x00\xc0\x0f\x24\xff\xe1\x35\xfc\x30\x2d\xcb\x82\x64\x48\x12\x46\x01\x7f\x26\x12\xe7\x50\x51\xfc\xb9
[...]
+var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x7d\x4f\x73\xdb\x38\xd2\xf7\x7d\x3e\x45\x57\x2e\x76\xde\x92\x9d\xdd\xd3\x5b\x4f\x52\x73\xd0\x24\x9e\x8d\x37\x89\xed\x8a\x9d\xd9\x9d\xda\x6c\x8d\x20\x12\x92\xb0\xa6\x00\x0e\x00\x5a\x51\xb2\xfe\xee\x4f\x01\x20\x29\x52\xc2\x5f\x52\x4e\x9e\x53\x1c\xb1\xfb\xd7\x0d\xa0\x01\x34\x1a\x0d\xe0\x5f\x3f\x01\x7c\xfb\x09\x00\xe0\x19\xc9\x9f\xbd\x84\x67\xd3\xb2\x2c\x48\x86\x24\x61\x14\xf0\x17\x22\x71\x0e\x15\xc5\x5f
[...]
 
 func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
     return bindataRead(
@@ -129,7 +129,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 49848, mode:
os.FileMode(420), modTime: time.Unix(1502310784, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 50834, mode:
os.FileMode(420), modTime: time.Unix(1502981211, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -149,7 +149,7 @@ func wski18nResourcesEs_esAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/es_ES.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/es_ES.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -169,7 +169,7 @@ func wski18nResourcesFr_frAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/fr_FR.all.json", size: 101, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/fr_FR.all.json", size: 101, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -189,7 +189,7 @@ func wski18nResourcesIt_itAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/it_IT.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/it_IT.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -209,7 +209,7 @@ func wski18nResourcesJa_jaAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/ja_JA.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/ja_JA.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -229,7 +229,7 @@ func wski18nResourcesKo_krAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/ko_KR.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/ko_KR.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -249,7 +249,7 @@ func wski18nResourcesPt_brAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/pt_BR.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/pt_BR.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -269,7 +269,7 @@ func wski18nResourcesZh_hansAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/zh_Hans.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/zh_Hans.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
@@ -289,7 +289,7 @@ func wski18nResourcesZh_hantAllJson() (*asset, error) {
         return nil, err
     }
 
-    info := bindataFileInfo{name: "wski18n/resources/zh_Hant.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502310633, 0)}
+    info := bindataFileInfo{name: "wski18n/resources/zh_Hant.all.json", size: 0, mode: os.FileMode(420),
modTime: time.Unix(1502980774, 0)}
     a := &asset{bytes: bytes, info: info}
     return a, nil
 }
diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json
index 78acda0..39551d0 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -1400,8 +1400,8 @@
     "translation": "display full description of each API"
   },
   {
-    "id": "An API host must be provided.",
-    "translation": "An API host must be provided."
+    "id": "order API list by action name first followed by base-path/rel-path/verb",
+    "translation": "order API list by action name first followed by base-path/rel-path/verb."
   },
   {
     "id": "Request accepted, but processing not completed yet.",
@@ -1510,9 +1510,16 @@
   {
     "id": "Unable to output bash command completion {{.err}}",
     "translation": "Unable to output bash command completion {{.err}}"
-},
-{
+  },
+  {
     "id": "prints bash command completion script to stdout",
     "translation": "prints bash command completion script to stdout"
-}
-]
+  },
+  {
+    "id": "sorts a list alphabetically by entity name; only applicable within the limit/skip
returned entity block",
+    "translation": "sorts a list alphabetically by entity name; only applicable within the
limit/skip returned entity block"
+  },
+  {
+    "id": "sorts a list alphabetically by order of [BASE_PATH | API_NAME], API_PATH, then
API_VERB; only applicable within the limit/skip returned entity block",
+    "translation": "sorts a list alphabetically by order of [BASE_PATH | API_NAME], API_PATH,
then API_VERB; only applicable within the limit/skip returned entity block"
+  }]

-- 
To stop receiving notification emails like this one, please contact
"commits@openwhisk.apache.org" <commits@openwhisk.apache.org>.

Mime
View raw message