You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by pe...@apache.org on 2025/04/03 13:23:34 UTC
(cloudstack-cloudmonkey) branch support-response-exlude-list-filtering created (now bdfbeb3)
This is an automated email from the ASF dual-hosted git repository.
pearl11594 pushed a change to branch support-response-exlude-list-filtering
in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git
at bdfbeb3 Add support for excluding a list of parameters from an API response
This branch includes the following new commits:
new bdfbeb3 Add support for excluding a list of parameters from an API response
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(cloudstack-cloudmonkey) 01/01: Add support for excluding a list of parameters from an API response
Posted by pe...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
pearl11594 pushed a commit to branch support-response-exlude-list-filtering
in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git
commit bdfbeb36c50025e3a560683e3eabafd6ec54dca7
Author: Pearl Dsilva <pe...@gmail.com>
AuthorDate: Thu Apr 3 09:23:20 2025 -0400
Add support for excluding a list of parameters from an API response
---
cli/completer.go | 17 ++++++++++++++
cmd/api.go | 15 ++++++++++--
cmd/output.go | 69 ++++++++++++++++++++++++++++++++++++--------------------
config/cache.go | 7 ++++++
4 files changed, 82 insertions(+), 26 deletions(-)
diff --git a/cli/completer.go b/cli/completer.go
index be1ba21..53de5fb 100644
--- a/cli/completer.go
+++ b/cli/completer.go
@@ -357,6 +357,7 @@ func (t *autoCompleter) Do(line []rune, pos int) (options [][]rune, offset int)
}
return
}
+
if arg.Type == config.FAKE && arg.Name == "filter=" {
offset = 0
filterInputs := strings.Split(strings.Replace(argInput, ",", ",|", -1), "|")
@@ -373,6 +374,22 @@ func (t *autoCompleter) Do(line []rune, pos int) (options [][]rune, offset int)
return
}
+ if arg.Type == config.FAKE && arg.Name == "exclude=" {
+ offset = 0
+ excludeFilterInputs := strings.Split(strings.Replace(argInput, ",", ",|", -1), "|")
+ lastExcludeFilterInput := lastString(excludeFilterInputs)
+ for _, key := range apiFound.ResponseKeys {
+ if inArray(key, excludeFilterInputs) {
+ continue
+ }
+ if strings.HasPrefix(key, lastExcludeFilterInput) {
+ options = append(options, []rune(key[len(lastExcludeFilterInput):]))
+ offset = len(lastExcludeFilterInput)
+ }
+ }
+ return
+ }
+
autocompleteAPI := findAutocompleteAPI(arg, apiFound, apiMap)
if autocompleteAPI == nil {
return nil, 0
diff --git a/cmd/api.go b/cmd/api.go
index 058c6fb..872a328 100644
--- a/cmd/api.go
+++ b/cmd/api.go
@@ -82,7 +82,7 @@ func init() {
if strings.HasSuffix(err.Error(), "context canceled") {
return nil
} else if response != nil {
- printResult(r.Config.Core.Output, response, nil)
+ printResult(r.Config.Core.Output, response, nil, nil)
}
return err
}
@@ -98,8 +98,19 @@ func init() {
}
}
+ var excludeKeys []string
+ for _, arg := range apiArgs {
+ if strings.HasPrefix(arg, "exclude=") {
+ for _, excludeKey := range strings.Split(strings.Split(arg, "=")[1], ",") {
+ if len(strings.TrimSpace(excludeKey)) > 0 {
+ excludeKeys = append(excludeKeys, strings.TrimSpace(excludeKey))
+ }
+ }
+ }
+ }
+
if len(response) > 0 {
- printResult(r.Config.Core.Output, response, filterKeys)
+ printResult(r.Config.Core.Output, response, filterKeys, excludeKeys)
}
return nil
diff --git a/cmd/output.go b/cmd/output.go
index 08004cf..f45e6d8 100644
--- a/cmd/output.go
+++ b/cmd/output.go
@@ -206,51 +206,72 @@ func printCsv(response map[string]interface{}, filter []string) {
enc.Flush()
}
-func filterResponse(response map[string]interface{}, filter []string, outputType string) map[string]interface{} {
- if filter == nil || len(filter) == 0 {
+func filterResponse(response map[string]interface{}, filter []string, excludeFilter []string, outputType string) map[string]interface{} {
+ // If no filtering is required, return the original response.
+ if len(filter) == 0 && len(excludeFilter) == 0 {
return response
}
+
+ // Create a set for excludeFilter to improve lookup performance.
+ excludeSet := make(map[string]struct{}, len(excludeFilter))
+ for _, key := range excludeFilter {
+ excludeSet[key] = struct{}{}
+ }
+
+ // Create a set for filter keys for fast lookup.
+ filterSet := make(map[string]struct{}, len(filter))
+ for _, key := range filter {
+ filterSet[key] = struct{}{}
+ }
+
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
- }
+
+ for key, value := range response {
+ // Process only slice/map values
+ switch items := value.(type) {
+ case []interface{}:
var filteredRows []interface{}
for _, item := range items {
row, ok := item.(map[string]interface{})
- if !ok || len(row) < 1 {
+ if !ok || len(row) == 0 {
continue
}
+
filteredRow := make(map[string]interface{})
- for _, filterKey := range filter {
- for field := range row {
- if filterKey == field {
- filteredRow[field] = row[field]
+
+ if len(filter) > 0 {
+ // Include only keys that exist in filterSet
+ for filterKey := range filterSet {
+ if val, exists := row[filterKey]; exists {
+ filteredRow[filterKey] = val
+ } else if outputType == config.COLUMN || outputType == config.CSV || outputType == config.TABLE {
+ filteredRow[filterKey] = "" // Ensure all filter keys exist in row
}
}
- if outputType == config.COLUMN || outputType == config.CSV || outputType == config.TABLE {
- if _, ok := filteredRow[filterKey]; !ok {
- filteredRow[filterKey] = ""
+ } else {
+ // Exclude keys from excludeFilter
+ for field, val := range row {
+ if _, excluded := excludeSet[field]; !excluded {
+ filteredRow[field] = val
}
}
}
+
filteredRows = append(filteredRows, filteredRow)
}
- filteredResponse[k] = filteredRows
- } else {
- filteredResponse[k] = v
- continue
- }
+ filteredResponse[key] = filteredRows
+ default:
+ // If it's not a slice, copy as is
+ filteredResponse[key] = value
+ }
}
+
return filteredResponse
}
-func printResult(outputType string, response map[string]interface{}, filter []string) {
- response = filterResponse(response, filter, outputType)
+func printResult(outputType string, response map[string]interface{}, filter []string, excludeFilter []string) {
+ response = filterResponse(response, filter, excludeFilter, outputType)
switch outputType {
case config.JSON:
printJSON(response)
diff --git a/config/cache.go b/config/cache.go
index 096582d..13596dd 100644
--- a/config/cache.go
+++ b/config/cache.go
@@ -151,6 +151,13 @@ func (c *Config) UpdateCache(response map[string]interface{}) interface{} {
Description: "cloudmonkey specific response key filtering",
})
+ // Add exclude arg
+ apiArgs = append(apiArgs, &APIArg{
+ Name: "exclude=",
+ Type: FAKE,
+ Description: "cloudmonkey specific response key to exlude when filtering",
+ })
+
sort.Slice(apiArgs, func(i, j int) bool {
return apiArgs[i].Name < apiArgs[j].Name
})