Changes to run_keyword:

- Allow multiple lib/resource paths separated by ":" for lib_file_path.
- Allow multiple keywords separated by " ; " for keyword_string.
- Add smarts to allow assignments (e.g. ${state}=  Get State).

Change-Id: Idf38edb18b6b0bec0e6cd53ebc0b420439931306
Signed-off-by: Michael Walsh <micwalsh@us.ibm.com>
diff --git a/extended/run_keyword.py b/extended/run_keyword.py
old mode 100755
new mode 100644
index 3f1a10b..38033c7
--- a/extended/run_keyword.py
+++ b/extended/run_keyword.py
@@ -4,11 +4,10 @@
 This module is the python counterpart to run_keyword.robot.
 """
 
-import gen_print as gp
 import gen_robot_print as grp
 import gen_robot_valid as grv
-
 from robot.libraries.BuiltIn import BuiltIn
+import re
 
 
 ###############################################################################
@@ -20,12 +19,34 @@
 
     setup()
 
-    keyword_string = BuiltIn().get_variable_value("${keyword_string}")
-    lib_file_path = BuiltIn().get_variable_value("${lib_file_path}")
+    # NOTE: During code review the following question was raised: Why support
+    # 1) variable assignments 2) multiple keywords?  Couldn't a user simply
+    # call this program twice to get what they need.  If necessary, the user
+    # could take the output of the first call and specify it as a literal on
+    # the second call.
+    #
+    # However, this approach would not work in all cases.  The following case
+    # would be such an example:
+    # Let's say the first keyword string is as follows:
+    # Create Dictionary  foo=bar
+    # You wish to take the output of that call and specify it as a literal
+    # value when running the following:
+    # Want Dictionary  parm=<literal dictionary specification>
+    # The problem is that there is no way to specify a dictionary as a
+    # literal in Robot Framework.
+    # By having this program support variable assignments and multiple
+    # keywords, the user can invoke it with the following keyword string.
+    # ${my_dict}=  Create Dictionary  foo=bar ; Want Dictionary  ${my_dict}
 
-    cmd_buf = keyword_string.split("  ")
+    # The user can pass multiple lib/resource paths by separating them with a
+    # colon.
 
-    if lib_file_path != "":
+    lib_file_path_list = \
+        BuiltIn().get_variable_value("${lib_file_path}").split(":")
+    # Get rid of empty entry if it exists.
+    if lib_file_path_list[0] == "":
+        del lib_file_path_list[0]
+    for lib_file_path in lib_file_path_list:
         # We don't want global variable getting changed when an import is done
         # so we'll save it and restore it.
         quiet = int(BuiltIn().get_variable_value("${quiet}"))
@@ -37,22 +58,33 @@
             BuiltIn().import_resource(lib_file_path)
         BuiltIn().set_global_variable("${quiet}", quiet)
 
-    error_message = grp.sprint_error_report("Keyword \"" + cmd_buf[0] +
-                                            "\" does not exist.\n")
-    BuiltIn().keyword_should_exist(cmd_buf[0], msg=error_message)
+    # The user can pass multiple keyword strings by separating them with " ; ".
+    keyword_list = \
+        BuiltIn().get_variable_value("${keyword_string}").split(" ; ")
+    for keyword_string in keyword_list:
+        cmd_buf = keyword_string.split("  ")
+        if re.match(r"\$\{", cmd_buf[0]):
+            # This looks like an assignment (e.g. ${var}=  <keyword>).
+            # We'll extract the variable name, remove element 0 from
+            # cmd_buf and set the global variable with the results
+            # after running the keyword.
+            var_name = cmd_buf[0].strip("${}=")
+            del cmd_buf[0]
+        else:
+            var_name = ""
 
-    grp.rqprint_issuing_keyword(cmd_buf)
-    status, output = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
-    if status != "PASS":
-        error_message = grp.sprint_error_report("\"" + cmd_buf[0] +
-                                                "\" failed with the" +
-                                                " following error:\n" + output)
-        if not quiet:
-            grp.rprint(error_message, 'STDERR')
-        BuiltIn().fail(error_message)
+        test_mode = int(BuiltIn().get_variable_value("${test_mode}"))
+        grp.rqprint_issuing_keyword(cmd_buf, test_mode)
+        if test_mode:
+            return
 
-    if output is not None:
-        grp.rprint(output)
+        output = BuiltIn().run_keyword(*cmd_buf)
+
+        if var_name != "":
+            BuiltIn().set_global_variable("${" + var_name + "}", output)
+        else:
+            if output is not None:
+                grp.rprint_var(output)
 
 ###############################################################################
 
diff --git a/extended/run_keyword.robot b/extended/run_keyword.robot
old mode 100755
new mode 100644
index 52924d1..cf45d29
--- a/extended/run_keyword.robot
+++ b/extended/run_keyword.robot
@@ -1,6 +1,31 @@
 *** Settings ***
 Documentation  Run the caller's keyword string.
 
+# Description of parameters:
+# keyword_string  The keyword string to be run by this program.  If this
+#                 keyword string contains " ; " anywhere, it will be taken to
+#                 be multiple keyword strings (see example below).  Each
+#                 keywrod may also include a variable assignment.  Example:
+#                 ${my_var}=  My Keyword
+# lib_file_path   The path to a library or resource needed to run the keywords.
+#                 This may contain a colon-delimited list of library/resource
+#                 paths.
+# test_mode       This means that this program should go through all the
+#                 motions but not actually do anything substantial.
+# debug           If this parameter is set to "1", this program will print
+#                 additional debug information.
+# quiet           If this parameter is set to "1", this program will print
+#                 only essential information, i.e. it will not echo parameters,
+#                 echo commands, print the total run time, etc.
+
+# Example calls:
+# cd $HOME/git/openbmc-test-automation
+# export PYTHONPATH=${HOME}/git/openbmc-test-automation/lib/
+
+# robot --outputdir=/tmp -v OPENBMC_HOST:barp01 -v 'keyword_string:Log To Console  Hi.' extended/run_keyword.robot
+
+# robot --outputdir=/tmp -v OPENBMC_HOST:barp01 -v 'keyword_string:${state}=  Get State  quiet=${1} ; Rpvar  state' -v lib_file_path:state.py extended/run_keyword.robot
+
 # NOTE: Robot searches PYTHONPATH for libraries.
 Library   run_keyword.py