1#!/usr/bin/env python 2 3r""" 4This module provides command execution functions such as cmd_fnc and cmd_fnc_u. 5""" 6 7import sys 8import subprocess 9import collections 10 11robot_env = 1 12try: 13 from robot.libraries.BuiltIn import BuiltIn 14except ImportError: 15 robot_env = 0 16import gen_print as gp 17import gen_valid as gv 18import gen_misc as gm 19if robot_env: 20 import gen_robot_print as grp 21 22 23############################################################################### 24def cmd_fnc(cmd_buf, 25 quiet=None, 26 test_mode=None, 27 debug=0, 28 print_output=1, 29 show_err=1): 30 31 r""" 32 Run the given command in a shell and return the shell return code. 33 34 Description of arguments: 35 cmd_buf The command string to be run in a shell. 36 quiet Indicates whether this function should run 37 the pissuing() 38 function prints an "Issuing: <cmd string>" to stdout. 39 test_mode If test_mode is set, this function will 40 not actually run 41 the command. 42 debug If debug is set, this function will print 43 extra debug info. 44 print_output If this is set, this function will print 45 the stdout/stderr 46 generated by the shell command. 47 show_err If show_err is set, this function will 48 print a standardized 49 error report if the shell command returns non-zero. 50 """ 51 52 quiet = int(gm.global_default(quiet, 0)) 53 test_mode = int(gm.global_default(test_mode, 0)) 54 55 if debug: 56 gp.print_vars(cmd_buf, quiet, test_mode, debug) 57 58 err_msg = gv.svalid_value(cmd_buf) 59 if err_msg != "": 60 raise ValueError(err_msg) 61 62 if not quiet: 63 gp.pissuing(cmd_buf, test_mode) 64 65 if test_mode: 66 return 0, "" 67 68 sub_proc = subprocess.Popen(cmd_buf, 69 bufsize=1, 70 shell=True, 71 stdout=subprocess.PIPE, 72 stderr=subprocess.STDOUT) 73 out_buf = "" 74 for line in sub_proc.stdout: 75 out_buf += line 76 if not print_output: 77 continue 78 if robot_env: 79 grp.rprint(line) 80 else: 81 sys.stdout.write(line) 82 if print_output and not robot_env: 83 sys.stdout.flush() 84 sub_proc.communicate() 85 shell_rc = sub_proc.returncode 86 if shell_rc != 0 and show_err: 87 if robot_env: 88 grp.rprint_error_report("The prior command failed.\n" + 89 gp.sprint_var(shell_rc, 1)) 90 else: 91 gp.print_error_report("The prior command failed.\n" + 92 gp.sprint_var(shell_rc, 1)) 93 94 return shell_rc, out_buf 95 96############################################################################### 97 98 99############################################################################### 100def cmd_fnc_u(cmd_buf, 101 quiet=None, 102 debug=None, 103 print_output=1, 104 show_err=1): 105 106 r""" 107 Call cmd_fnc with test_mode=0. See cmd_fnc (above) for details. 108 109 Note the "u" in "cmd_fnc_u" stands for "unconditional". 110 """ 111 112 return cmd_fnc(cmd_buf, test_mode=0, quiet=quiet, debug=debug, 113 print_output=print_output, show_err=show_err) 114 115############################################################################### 116 117 118############################################################################### 119def parse_command_string(command_string): 120 121 r""" 122 Parse a bash command-line command string and return the result as a 123 dictionary of parms. 124 125 This can be useful for answering questions like "What did the user specify 126 as the value for parm x in the command string?". 127 128 This function expects the command string to follow the following posix 129 conventions: 130 - Short parameters: 131 -<parm name><space><arg value> 132 - Long parameters: 133 --<parm name>=<arg value> 134 135 The first item in the string will be considered to be the command. All 136 values not conforming to the specifications above will be considered 137 positional parms. If there are multiple parms with the same name, they 138 will be put into a list (see illustration below where "-v" is specified 139 multiple times). 140 141 Description of argument(s): 142 command_string The complete command string including all 143 parameters and arguments. 144 145 Sample input: 146 147 robot_cmd_buf: robot -v 148 OPENBMC_HOST:dummy1 -v keyword_string:'Set Auto Reboot no' -v 149 lib_file_path:/home/user1/git/openbmc-test-automation/lib/utils.robot -v 150 quiet:0 -v test_mode:0 -v debug:0 151 --outputdir='/home/user1/status/children/' 152 --output=dummy1.Auto_reboot.170802.124544.output.xml 153 --log=dummy1.Auto_reboot.170802.124544.log.html 154 --report=dummy1.Auto_reboot.170802.124544.report.html 155 /home/user1/git/openbmc-test-automation/extended/run_keyword.robot 156 157 Sample output: 158 159 robot_cmd_buf_dict: 160 robot_cmd_buf_dict[command]: robot 161 robot_cmd_buf_dict[v]: 162 robot_cmd_buf_dict[v][0]: OPENBMC_HOST:dummy1 163 robot_cmd_buf_dict[v][1]: keyword_string:Set Auto 164 Reboot no 165 robot_cmd_buf_dict[v][2]: 166 lib_file_path:/home/user1/git/openbmc-test-automation/lib/utils.robot 167 robot_cmd_buf_dict[v][3]: quiet:0 168 robot_cmd_buf_dict[v][4]: test_mode:0 169 robot_cmd_buf_dict[v][5]: debug:0 170 robot_cmd_buf_dict[outputdir]: 171 /home/user1/status/children/ 172 robot_cmd_buf_dict[output]: 173 dummy1.Auto_reboot.170802.124544.output.xml 174 robot_cmd_buf_dict[log]: 175 dummy1.Auto_reboot.170802.124544.log.html 176 robot_cmd_buf_dict[report]: 177 dummy1.Auto_reboot.170802.124544.report.html 178 robot_cmd_buf_dict[positional]: 179 /home/user1/git/openbmc-test-automation/extended/run_keyword.robot 180 """ 181 182 # We want the parms in the string broken down the way bash would do it, 183 # so we'll call upon bash to do that by creating a simple inline bash 184 # function. 185 bash_func_def = "function parse { for parm in \"${@}\" ; do" +\ 186 " echo $parm ; done ; }" 187 188 rc, outbuf = cmd_fnc_u(bash_func_def + " ; parse " + command_string, 189 quiet=1, print_output=0) 190 command_string_list = outbuf.rstrip("\n").split("\n") 191 192 command_string_dict = collections.OrderedDict() 193 ix = 1 194 command_string_dict['command'] = command_string_list[0] 195 while ix < len(command_string_list): 196 if command_string_list[ix].startswith("--"): 197 key, value = command_string_list[ix].split("=") 198 key = key.lstrip("-") 199 elif command_string_list[ix].startswith("-"): 200 key = command_string_list[ix].lstrip("-") 201 ix += 1 202 try: 203 value = command_string_list[ix] 204 except IndexError: 205 value = "" 206 else: 207 key = 'positional' 208 value = command_string_list[ix] 209 if key in command_string_dict: 210 if type(command_string_dict[key]) is str: 211 command_string_dict[key] = [command_string_dict[key]] 212 command_string_dict[key].append(value) 213 else: 214 command_string_dict[key] = value 215 ix += 1 216 217 return command_string_dict 218 219############################################################################### 220