blob: b5c5341b25bda269595e7156f91667fb294c5803 [file] [log] [blame]
Michael Walshc3b512e2017-02-20 15:59:01 -06001#!/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
Michael Walshf41fac82017-08-02 15:05:24 -05009import collections
Michael Walshc3b512e2017-02-20 15:59:01 -060010
11robot_env = 1
12try:
Michael Walshc3b512e2017-02-20 15:59:01 -060013 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
Michael Walshafc53a22017-04-12 15:52:28 -050019if robot_env:
20 import gen_robot_print as grp
Michael Walshc3b512e2017-02-20 15:59:01 -060021
22
23###############################################################################
24def cmd_fnc(cmd_buf,
25 quiet=None,
26 test_mode=None,
Michael Walshafc53a22017-04-12 15:52:28 -050027 debug=0,
Michael Walshc3b512e2017-02-20 15:59:01 -060028 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))
Michael Walshc3b512e2017-02-20 15:59:01 -060054
55 if debug:
Michael Walshafc53a22017-04-12 15:52:28 -050056 gp.print_vars(cmd_buf, quiet, test_mode, debug)
Michael Walshc3b512e2017-02-20 15:59:01 -060057
58 err_msg = gv.svalid_value(cmd_buf)
59 if err_msg != "":
60 raise ValueError(err_msg)
61
62 if not quiet:
Michael Walshafc53a22017-04-12 15:52:28 -050063 gp.pissuing(cmd_buf, test_mode)
Michael Walshc3b512e2017-02-20 15:59:01 -060064
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###############################################################################
Michael Walshf41fac82017-08-02 15:05:24 -0500116
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###############################################################################