|  | #!/usr/bin/env python | 
|  |  | 
|  | r""" | 
|  | This module provides command execution functions such as cmd_fnc and cmd_fnc_u. | 
|  | """ | 
|  |  | 
|  | import sys | 
|  | import subprocess | 
|  | import collections | 
|  |  | 
|  | robot_env = 1 | 
|  | try: | 
|  | from robot.libraries.BuiltIn import BuiltIn | 
|  | except ImportError: | 
|  | robot_env = 0 | 
|  | import gen_print as gp | 
|  | import gen_valid as gv | 
|  | import gen_misc as gm | 
|  | if robot_env: | 
|  | import gen_robot_print as grp | 
|  |  | 
|  |  | 
|  | ############################################################################### | 
|  | def cmd_fnc(cmd_buf, | 
|  | quiet=None, | 
|  | test_mode=None, | 
|  | debug=0, | 
|  | print_output=1, | 
|  | show_err=1): | 
|  |  | 
|  | r""" | 
|  | Run the given command in a shell and return the shell return code. | 
|  |  | 
|  | Description of arguments: | 
|  | cmd_buf                         The command string to be run in a shell. | 
|  | quiet                           Indicates whether this function should run | 
|  | the pissuing() | 
|  | function prints an "Issuing: <cmd string>" to stdout. | 
|  | test_mode                       If test_mode is set, this function will | 
|  | not actually run | 
|  | the command. | 
|  | debug                           If debug is set, this function will print | 
|  | extra debug info. | 
|  | print_output                    If this is set, this function will print | 
|  | the stdout/stderr | 
|  | generated by the shell command. | 
|  | show_err                        If show_err is set, this function will | 
|  | print a standardized | 
|  | error report if the shell command returns non-zero. | 
|  | """ | 
|  |  | 
|  | quiet = int(gm.global_default(quiet, 0)) | 
|  | test_mode = int(gm.global_default(test_mode, 0)) | 
|  |  | 
|  | if debug: | 
|  | gp.print_vars(cmd_buf, quiet, test_mode, debug) | 
|  |  | 
|  | err_msg = gv.svalid_value(cmd_buf) | 
|  | if err_msg != "": | 
|  | raise ValueError(err_msg) | 
|  |  | 
|  | if not quiet: | 
|  | gp.pissuing(cmd_buf, test_mode) | 
|  |  | 
|  | if test_mode: | 
|  | return 0, "" | 
|  |  | 
|  | sub_proc = subprocess.Popen(cmd_buf, | 
|  | bufsize=1, | 
|  | shell=True, | 
|  | stdout=subprocess.PIPE, | 
|  | stderr=subprocess.STDOUT) | 
|  | out_buf = "" | 
|  | for line in sub_proc.stdout: | 
|  | out_buf += line | 
|  | if not print_output: | 
|  | continue | 
|  | if robot_env: | 
|  | grp.rprint(line) | 
|  | else: | 
|  | sys.stdout.write(line) | 
|  | if print_output and not robot_env: | 
|  | sys.stdout.flush() | 
|  | sub_proc.communicate() | 
|  | shell_rc = sub_proc.returncode | 
|  | if shell_rc != 0 and show_err: | 
|  | if robot_env: | 
|  | grp.rprint_error_report("The prior command failed.\n" + | 
|  | gp.sprint_var(shell_rc, 1)) | 
|  | else: | 
|  | gp.print_error_report("The prior command failed.\n" + | 
|  | gp.sprint_var(shell_rc, 1)) | 
|  |  | 
|  | return shell_rc, out_buf | 
|  |  | 
|  | ############################################################################### | 
|  |  | 
|  |  | 
|  | ############################################################################### | 
|  | def cmd_fnc_u(cmd_buf, | 
|  | quiet=None, | 
|  | debug=None, | 
|  | print_output=1, | 
|  | show_err=1): | 
|  |  | 
|  | r""" | 
|  | Call cmd_fnc with test_mode=0.  See cmd_fnc (above) for details. | 
|  |  | 
|  | Note the "u" in "cmd_fnc_u" stands for "unconditional". | 
|  | """ | 
|  |  | 
|  | return cmd_fnc(cmd_buf, test_mode=0, quiet=quiet, debug=debug, | 
|  | print_output=print_output, show_err=show_err) | 
|  |  | 
|  | ############################################################################### | 
|  |  | 
|  |  | 
|  | ############################################################################### | 
|  | def parse_command_string(command_string): | 
|  |  | 
|  | r""" | 
|  | Parse a bash command-line command string and return the result as a | 
|  | dictionary of parms. | 
|  |  | 
|  | This can be useful for answering questions like "What did the user specify | 
|  | as the value for parm x in the command string?". | 
|  |  | 
|  | This function expects the command string to follow the following posix | 
|  | conventions: | 
|  | - Short parameters: | 
|  | -<parm name><space><arg value> | 
|  | - Long parameters: | 
|  | --<parm name>=<arg value> | 
|  |  | 
|  | The first item in the string will be considered to be the command.  All | 
|  | values not conforming to the specifications above will be considered | 
|  | positional parms.  If there are multiple parms with the same name, they | 
|  | will be put into a list (see illustration below where "-v" is specified | 
|  | multiple times). | 
|  |  | 
|  | Description of argument(s): | 
|  | command_string                  The complete command string including all | 
|  | parameters and arguments. | 
|  |  | 
|  | Sample input: | 
|  |  | 
|  | robot_cmd_buf:                                    robot -v | 
|  | OPENBMC_HOST:dummy1 -v keyword_string:'Set Auto Reboot  no' -v | 
|  | lib_file_path:/home/user1/git/openbmc-test-automation/lib/utils.robot -v | 
|  | quiet:0 -v test_mode:0 -v debug:0 | 
|  | --outputdir='/home/user1/status/children/' | 
|  | --output=dummy1.Auto_reboot.170802.124544.output.xml | 
|  | --log=dummy1.Auto_reboot.170802.124544.log.html | 
|  | --report=dummy1.Auto_reboot.170802.124544.report.html | 
|  | /home/user1/git/openbmc-test-automation/extended/run_keyword.robot | 
|  |  | 
|  | Sample output: | 
|  |  | 
|  | robot_cmd_buf_dict: | 
|  | robot_cmd_buf_dict[command]:                    robot | 
|  | robot_cmd_buf_dict[v]: | 
|  | robot_cmd_buf_dict[v][0]:                     OPENBMC_HOST:dummy1 | 
|  | robot_cmd_buf_dict[v][1]:                     keyword_string:Set Auto | 
|  | Reboot no | 
|  | robot_cmd_buf_dict[v][2]: | 
|  | lib_file_path:/home/user1/git/openbmc-test-automation/lib/utils.robot | 
|  | robot_cmd_buf_dict[v][3]:                     quiet:0 | 
|  | robot_cmd_buf_dict[v][4]:                     test_mode:0 | 
|  | robot_cmd_buf_dict[v][5]:                     debug:0 | 
|  | robot_cmd_buf_dict[outputdir]: | 
|  | /home/user1/status/children/ | 
|  | robot_cmd_buf_dict[output]: | 
|  | dummy1.Auto_reboot.170802.124544.output.xml | 
|  | robot_cmd_buf_dict[log]: | 
|  | dummy1.Auto_reboot.170802.124544.log.html | 
|  | robot_cmd_buf_dict[report]: | 
|  | dummy1.Auto_reboot.170802.124544.report.html | 
|  | robot_cmd_buf_dict[positional]: | 
|  | /home/user1/git/openbmc-test-automation/extended/run_keyword.robot | 
|  | """ | 
|  |  | 
|  | # We want the parms in the string broken down the way bash would do it, | 
|  | # so we'll call upon bash to do that by creating a simple inline bash | 
|  | # function. | 
|  | bash_func_def = "function parse { for parm in \"${@}\" ; do" +\ | 
|  | " echo $parm ; done ; }" | 
|  |  | 
|  | rc, outbuf = cmd_fnc_u(bash_func_def + " ; parse " + command_string, | 
|  | quiet=1, print_output=0) | 
|  | command_string_list = outbuf.rstrip("\n").split("\n") | 
|  |  | 
|  | command_string_dict = collections.OrderedDict() | 
|  | ix = 1 | 
|  | command_string_dict['command'] = command_string_list[0] | 
|  | while ix < len(command_string_list): | 
|  | if command_string_list[ix].startswith("--"): | 
|  | key, value = command_string_list[ix].split("=") | 
|  | key = key.lstrip("-") | 
|  | elif command_string_list[ix].startswith("-"): | 
|  | key = command_string_list[ix].lstrip("-") | 
|  | ix += 1 | 
|  | try: | 
|  | value = command_string_list[ix] | 
|  | except IndexError: | 
|  | value = "" | 
|  | else: | 
|  | key = 'positional' | 
|  | value = command_string_list[ix] | 
|  | if key in command_string_dict: | 
|  | if type(command_string_dict[key]) is str: | 
|  | command_string_dict[key] = [command_string_dict[key]] | 
|  | command_string_dict[key].append(value) | 
|  | else: | 
|  | command_string_dict[key] = value | 
|  | ix += 1 | 
|  |  | 
|  | return command_string_dict | 
|  |  | 
|  | ############################################################################### |