This is an automated email from the ASF dual-hosted git repository. houshengbo pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-cli.git
The following commit(s) were added to refs/heads/master by this push: new 72bc486 Refactor action invoke functions (#319) 72bc486 is described below commit 72bc4862db7188b669fdf8e82851f9dadf8f49fb Author: rodric rabbah <rod...@gmail.com> AuthorDate: Mon Jun 18 12:37:23 2018 -0400 Refactor action invoke functions (#319) * Refactor invoke functions. This permits invoking an action without access to global pamareters and bypassing parameter passing. Caller will be responsible for passing in the appropriate paramters, as in the case of a feed. * Strip references to Flags.common in utility methods for actions. * Add exit on error utility function. * update git ignore for tests/out. * Use refactored action invoke function but preserve semantics. * Pull out getParameters method to utils and use it in action invoke and trigger feed. * Refactor method printing activation response. --- .gitignore | 1 + commands/action.go | 120 +++++++++++++++++++++++++++++----------------------- commands/trigger.go | 29 ++++++++----- commands/util.go | 96 +++++++++++++++++++++++++++++++++++++++++ main.go | 46 +------------------- 5 files changed, 182 insertions(+), 110 deletions(-) diff --git a/.gitignore b/.gitignore index 55423b3..717c0b4 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ incubator-openwhisk-cli.iml wski18n/i18n_resources.go bin/ tests/build/ +tests/out/ diff --git a/commands/action.go b/commands/action.go index bce0bf2..c21d946 100644 --- a/commands/action.go +++ b/commands/action.go @@ -155,9 +155,8 @@ var actionInvokeCmd = &cobra.Command{ PreRunE: SetupClientConfig, RunE: func(cmd *cobra.Command, args []string) error { var err error - var parameters interface{} var qualifiedName = new(QualifiedName) - var paramArgs []string + var parameters interface{} if whiskErr := CheckArgs( args, @@ -172,65 +171,79 @@ var actionInvokeCmd = &cobra.Command{ return NewQualifiedNameError(args[0], err) } - Client.Namespace = qualifiedName.GetNamespace() - paramArgs = Flags.common.param + parameters = getParameters(Flags.common.param, false, false) + blocking := Flags.common.blocking || Flags.action.result + resultOnly := Flags.action.result + header := !resultOnly - if len(paramArgs) > 0 { - if parameters, err = getJSONFromStrings(paramArgs, false); err != nil { - return getJSONFromStringsParamError(paramArgs, false, err) - } - } - if Flags.action.result { - Flags.common.blocking = true - } - - res, _, err := Client.Actions.Invoke( - qualifiedName.GetEntityName(), + res, err := invokeAction( + *qualifiedName, parameters, - Flags.common.blocking, - Flags.action.result) + blocking, + resultOnly) - return handleInvocationResponse(*qualifiedName, parameters, res, err) + return printInvocationResponse(*qualifiedName, blocking, header, res, err) }, } -func handleInvocationResponse( +func invokeAction( qualifiedName QualifiedName, parameters interface{}, + blocking bool, + result bool) (map[string]interface{}, error) { + // TODO remove all global modifiers + Client.Namespace = qualifiedName.GetNamespace() + res, _, err := Client.Actions.Invoke( + qualifiedName.GetEntityName(), + parameters, + blocking, + result) + return res, err +} + +func printInvocationResponse( + qualifiedName QualifiedName, + blocking bool, + header bool, result map[string]interface{}, err error) error { if err == nil { - printInvocationMsg( - qualifiedName.GetNamespace(), - qualifiedName.GetEntityName(), - getValueFromJSONResponse(ACTIVATION_ID, result), - result, - color.Output) + printInvocationMsg(qualifiedName, blocking, header, result, color.Output) } else { - if !Flags.common.blocking { - return handleInvocationError(err, qualifiedName.GetEntityName(), parameters) + if !blocking { + return handleInvocationError(err, qualifiedName.GetEntityName()) } else { - if isBlockingTimeout(err) { - printBlockingTimeoutMsg( - qualifiedName.GetNamespace(), - qualifiedName.GetEntityName(), - getValueFromJSONResponse(ACTIVATION_ID, result)) - } else if isApplicationError(err) { - printInvocationMsg( - qualifiedName.GetNamespace(), - qualifiedName.GetEntityName(), - getValueFromJSONResponse(ACTIVATION_ID, result), - result, - colorable.NewColorableStderr()) - } else { - return handleInvocationError(err, qualifiedName.GetEntityName(), parameters) - } + return printFailedBlockingInvocationResponse(qualifiedName, header, result, err) } } return err } +func printFailedBlockingInvocationResponse( + qualifiedName QualifiedName, + header bool, + result map[string]interface{}, + err error) error { + if isBlockingTimeout(err) { + printBlockingTimeoutMsg( + qualifiedName.GetNamespace(), + qualifiedName.GetEntityName(), + getValueFromJSONResponse(ACTIVATION_ID, result)) + return err + } else if isApplicationError(err) { + printInvocationMsg( + qualifiedName, + true, + header, + result, + colorable.NewColorableStderr()) + return err + } else { + return handleInvocationError(err, qualifiedName.GetEntityName()) + } +} + var actionGetCmd = &cobra.Command{ Use: "get ACTION_NAME [FIELD_FILTER | --summary | --url]", Short: wski18n.T("get action"), @@ -987,12 +1000,11 @@ func actionGetError(entityName string, fetchCode bool, err error) error { return nestedError(errMsg, err) } -func handleInvocationError(err error, entityName string, parameters interface{}) error { +func handleInvocationError(err error, entityName string) error { whisk.Debug( whisk.DbgError, - "Client.Actions.Invoke(%s, %s, %t) error: %s\n", - entityName, parameters, - Flags.common.blocking, + "Client.Actions.Invoke(%s, %t) error: %s\n", + entityName, err) errMsg := wski18n.T( @@ -1113,25 +1125,25 @@ func printBlockingTimeoutMsg(namespace string, entityName string, activationID i } func printInvocationMsg( - namespace string, - entityName string, - activationID interface{}, + qualifiedName QualifiedName, + blocking bool, + header bool, response map[string]interface{}, outputStream io.Writer) { - if !Flags.action.result { + if header { fmt.Fprintf( outputStream, wski18n.T( "{{.ok}} invoked /{{.namespace}}/{{.name}} with id {{.id}}\n", map[string]interface{}{ "ok": color.GreenString("ok:"), - "namespace": boldString(namespace), - "name": boldString(entityName), - "id": boldString(activationID), + "namespace": boldString(qualifiedName.GetNamespace()), + "name": boldString(qualifiedName.GetEntityName()), + "id": boldString(getValueFromJSONResponse(ACTIVATION_ID, response)), })) } - if Flags.common.blocking { + if blocking { printJSON(response, outputStream) } } diff --git a/commands/trigger.go b/commands/trigger.go index fb50161..9aa0825 100644 --- a/commands/trigger.go +++ b/commands/trigger.go @@ -193,7 +193,7 @@ var triggerCreateCmd = &cobra.Command{ // Invoke the specified feed action to configure the trigger feed if feedArgPassed { - err := configureFeed(trigger.Name, fullFeedName) + err := configureFeed(trigger.Name, fullFeedName, getParameters(Flags.common.param, false, false)) if err != nil { whisk.Debug(whisk.DbgError, "configureFeed(%s, %s) failed: %s\n", trigger.Name, Flags.common.feed, err) @@ -286,7 +286,7 @@ var triggerUpdateCmd = &cobra.Command{ Flags.common.param = append(Flags.common.param, getFormattedJSON(FEED_AUTH_KEY, Client.Config.AuthToken)) // Invoke the specified feed action to configure the trigger feed - err = configureFeed(qualifiedName.GetEntityName(), fullFeedName) + err = configureFeed(qualifiedName.GetEntityName(), fullFeedName, getParameters(Flags.common.param, false, false)) if err != nil { whisk.Debug(whisk.DbgError, "configureFeed(%s, %s) failed: %s\n", qualifiedName.GetEntityName(), Flags.common.feed, err) @@ -372,7 +372,7 @@ var triggerGetCmd = &cobra.Command{ Flags.common.param = append(Flags.common.param, getFormattedJSON(FEED_TRIGGER_NAME, fullTriggerName)) Flags.common.param = append(Flags.common.param, getFormattedJSON(FEED_AUTH_KEY, Client.Config.AuthToken)) - err = configureFeed(qualifiedName.GetEntityName(), fullFeedName) + err = configureFeed(qualifiedName.GetEntityName(), fullFeedName, getParameters(Flags.common.param, false, false)) if err != nil { whisk.Debug(whisk.DbgError, "configureFeed(%s, %s) failed: %s\n", qualifiedName.GetEntityName(), fullFeedName, err) } @@ -441,7 +441,7 @@ var triggerDeleteCmd = &cobra.Command{ Flags.common.param = append(Flags.common.param, getFormattedJSON(FEED_TRIGGER_NAME, fullTriggerName)) Flags.common.param = append(Flags.common.param, getFormattedJSON(FEED_AUTH_KEY, Client.Config.AuthToken)) - err = configureFeed(qualifiedName.GetEntityName(), fullFeedName) + err = configureFeed(qualifiedName.GetEntityName(), fullFeedName, getParameters(Flags.common.param, false, false)) if err != nil { whisk.Debug(whisk.DbgError, "configureFeed(%s, %s) failed: %s\n", qualifiedName.GetEntityName(), fullFeedName, err) } @@ -515,17 +515,24 @@ var triggerListCmd = &cobra.Command{ }, } -func configureFeed(triggerName string, FullFeedName string) error { - feedArgs := []string{FullFeedName} - Flags.common.blocking = true - err := actionInvokeCmd.RunE(nil, feedArgs) +func configureFeed(triggerName string, feedName string, parameters interface{}) error { + var fullFeedName *QualifiedName + var err error + + if fullFeedName, err = NewQualifiedName(feedName); err != nil { + return NewQualifiedNameError(feedName, err) + } + + res, err := invokeAction(*fullFeedName, parameters, true, false) + err = printInvocationResponse(*fullFeedName, true, false, res, err) + if err != nil { - whisk.Debug(whisk.DbgError, "Invoke of action '%s' failed: %s\n", FullFeedName, err) + whisk.Debug(whisk.DbgError, "Invoke of action '%s' failed: %s\n", feedName, err) errStr := wski18n.T("Unable to invoke trigger '{{.trigname}}' feed action '{{.feedname}}'; feed is not configured: {{.err}}", - map[string]interface{}{"trigname": triggerName, "feedname": FullFeedName, "err": err}) + map[string]interface{}{"trigname": triggerName, "feedname": feedName, "err": err}) err = whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) } else { - whisk.Debug(whisk.DbgInfo, "Successfully configured trigger feed via feed action '%s'\n", FullFeedName) + whisk.Debug(whisk.DbgInfo, "Successfully configured trigger feed via feed action '%s'\n", feedName) } return err diff --git a/commands/util.go b/commands/util.go index a33ad23..775989b 100644 --- a/commands/util.go +++ b/commands/util.go @@ -27,6 +27,8 @@ import ( "github.com/apache/incubator-openwhisk-client-go/whisk" "github.com/fatih/color" + "github.com/mattn/go-colorable" + //prettyjson "github.com/hokaccha/go-prettyjson" // See prettyjson comment below "archive/tar" "archive/zip" @@ -51,6 +53,45 @@ func csvToQualifiedActions(artifacts string) []string { return res } +/** + * Processes command line to retrieve pairs of key-value pairs, where the value must be valid JSON. + * + * Parameters and annotations are handled the same way. The flag here is only for generating an error messages + * specific to one or the other. + * + * NOTE: this function will exit in case of a processing error since it indicates a problem parsing parameters. + * + * @return either an array or a JSON object (map) formatted representation of the key-value pairs. + */ +func getParameters(params []string, keyValueFormat bool, annotation bool) interface{} { + var parameters interface{} + var err error + + if !annotation { + whisk.Debug(whisk.DbgInfo, "Parsing parameters: %#v\n", params) + } else { + whisk.Debug(whisk.DbgInfo, "Parsing annotations: %#v\n", params) + } + + parameters, err = getJSONFromStrings(params, keyValueFormat) + if err != nil { + whisk.Debug(whisk.DbgError, "getJSONFromStrings(%#v, %s) failed: %s\n", params, keyValueFormat, err) + var errStr string + + if !annotation { + errStr = wski18n.T("Invalid parameter argument '{{.param}}': {{.err}}", + map[string]interface{}{"param": fmt.Sprintf("%#v", params), "err": err}) + } else { + errStr = wski18n.T("Invalid annotation argument '{{.annotation}}': {{.err}}", + map[string]interface{}{"annotation": fmt.Sprintf("%#v", params), "err": err}) + } + werr := whisk.MakeWskErrorFromWskError(errors.New(errStr), err, whisk.EXIT_CODE_ERR_GENERAL, whisk.DISPLAY_MSG, whisk.DISPLAY_USAGE) + ExitOnError(werr) + } + + return parameters +} + func getJSONFromStrings(content []string, keyValueFormat bool) (interface{}, error) { var data map[string]interface{} var res interface{} @@ -68,6 +109,10 @@ func getJSONFromStrings(content []string, keyValueFormat bool) (interface{}, err whisk.Debug(whisk.DbgInfo, "Created map '%v' from '%v'\n", data, content[i]) } + if data == nil { + data = make(map[string]interface{}) + } + if keyValueFormat { res = getKeyValueFormattedJSON(data) } else { @@ -1133,3 +1178,54 @@ func contains(arr []string, element string) bool { } return false } + +func ExitOnError(err error) { + if err == nil { + return + } + + whisk.Debug(whisk.DbgInfo, "err object type: %s\n", reflect.TypeOf(err).String()) + + T := wski18n.T + var exitCode int = 0 + var displayUsage bool = false + var displayMsg bool = false + var msgDisplayed bool = true + var displayPrefix bool = true + + werr, isWskError := err.(*whisk.WskError) // Is the err a WskError? + if isWskError { + whisk.Debug(whisk.DbgError, "Got a *whisk.WskError error: %#v\n", werr) + displayUsage = werr.DisplayUsage + displayMsg = werr.DisplayMsg + msgDisplayed = werr.MsgDisplayed + displayPrefix = werr.DisplayPrefix + exitCode = werr.ExitCode + } else { + whisk.Debug(whisk.DbgError, "Got some other error: %s\n", err) + fmt.Fprintf(os.Stderr, "%s\n", err) + + displayUsage = false // Cobra already displayed the usage message + exitCode = 1 + } + + outputStream := colorable.NewColorableStderr() + + // If the err msg should be displayed to the console and it has not already been + // displayed, display it now. + if displayMsg && !msgDisplayed && displayPrefix && exitCode != 0 { + fmt.Fprintf(outputStream, "%s%s\n", color.RedString(T("error: ")), err) + } else if displayMsg && !msgDisplayed && !displayPrefix && exitCode != 0 { + fmt.Fprintf(outputStream, "%s\n", err) + } else if displayMsg && !msgDisplayed && exitCode == 0 { + fmt.Fprintf(outputStream, "%s\n", err) + } + + // Displays usage + if displayUsage { + fmt.Fprintf(outputStream, T("Run '{{.Name}} --help' for usage.\n", + map[string]interface{}{"Name": WskCmd.CommandPath()})) + } + + os.Exit(exitCode) +} diff --git a/main.go b/main.go index 526c505..343f6c6 100644 --- a/main.go +++ b/main.go @@ -19,15 +19,12 @@ package main import ( "fmt" - "github.com/fatih/color" goi18n "github.com/nicksnyder/go-i18n/i18n" "os" - "reflect" "github.com/apache/incubator-openwhisk-cli/commands" "github.com/apache/incubator-openwhisk-cli/wski18n" "github.com/apache/incubator-openwhisk-client-go/whisk" - "github.com/mattn/go-colorable" ) // CLI_BUILD_TIME holds the time of the CLI build. During gradle builds, @@ -51,12 +48,6 @@ func init() { } func main() { - var exitCode int = 0 - var displayUsage bool = false - var displayMsg bool = false - var msgDisplayed bool = true - var displayPrefix bool = true - defer func() { if r := recover(); r != nil { fmt.Println(r) @@ -65,42 +56,7 @@ func main() { }() if err := commands.Execute(); err != nil { - whisk.Debug(whisk.DbgInfo, "err object type: %s\n", reflect.TypeOf(err).String()) - - werr, isWskError := err.(*whisk.WskError) // Is the err a WskError? - if isWskError { - whisk.Debug(whisk.DbgError, "Got a *whisk.WskError error: %#v\n", werr) - displayUsage = werr.DisplayUsage - displayMsg = werr.DisplayMsg - msgDisplayed = werr.MsgDisplayed - displayPrefix = werr.DisplayPrefix - exitCode = werr.ExitCode - } else { - whisk.Debug(whisk.DbgError, "Got some other error: %s\n", err) - fmt.Fprintf(os.Stderr, "%s\n", err) - - displayUsage = false // Cobra already displayed the usage message - exitCode = 1 - } - - outputStream := colorable.NewColorableStderr() - - // If the err msg should be displayed to the console and it has not already been - // displayed, display it now. - if displayMsg && !msgDisplayed && displayPrefix && exitCode != 0 { - fmt.Fprintf(outputStream, "%s%s\n", color.RedString(T("error: ")), err) - } else if displayMsg && !msgDisplayed && !displayPrefix && exitCode != 0 { - fmt.Fprintf(outputStream, "%s\n", err) - } else if displayMsg && !msgDisplayed && exitCode == 0 { - fmt.Fprintf(outputStream, "%s\n", err) - } - - // Displays usage - if displayUsage { - fmt.Fprintf(outputStream, T("Run '{{.Name}} --help' for usage.\n", - map[string]interface{}{"Name": commands.WskCmd.CommandPath()})) - } + commands.ExitOnError(err) } - os.Exit(exitCode) return } -- To stop receiving notification emails like this one, please contact houshen...@apache.org.