blob: d045ba9a72b31b2166646ce29790fed3c917fab9 [file] [log] [blame]
Michael Walshde791732016-09-06 14:25:24 -05001#!/usr/bin/env python
2
Michael Walsh7423c012016-10-04 10:27:21 -05003r"""
4This module provides many valuable functions such as my_parm_file.
5"""
Michael Walshde791732016-09-06 14:25:24 -05006
7# sys and os are needed to get the program dir path and program name.
8import sys
Michael Walsheaa16852017-09-19 16:30:43 -05009import errno
Michael Walshde791732016-09-06 14:25:24 -050010import os
11import ConfigParser
12import StringIO
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060013import re
Michael Walsh1c85bab2017-05-04 14:29:24 -050014import socket
Michael Walshde791732016-09-06 14:25:24 -050015
Michael Walsh7423c012016-10-04 10:27:21 -050016import gen_print as gp
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060017import gen_cmd as gc
18
Michael Walsh93a09f22017-11-13 15:34:46 -060019robot_env = gp.robot_env
20if robot_env:
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060021 from robot.libraries.BuiltIn import BuiltIn
Michael Walsh7423c012016-10-04 10:27:21 -050022
Michael Walshde791732016-09-06 14:25:24 -050023
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060024def add_trailing_slash(dir_path):
Michael Walsh7db77942017-01-10 11:37:06 -060025
26 r"""
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060027 Add a trailing slash to the directory path if it doesn't already have one
28 and return it.
Michael Walsh7db77942017-01-10 11:37:06 -060029
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060030 Description of arguments:
31 dir_path A directory path.
Michael Walsh7db77942017-01-10 11:37:06 -060032 """
33
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060034 return os.path.normpath(dir_path) + os.path.sep
35
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060036
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060037def which(file_path):
38
39 r"""
40 Find the full path of an executable file and return it.
41
42 The PATH environment variable dictates the results of this function.
43
44 Description of arguments:
45 file_path The relative file path (e.g. "my_file" or
46 "lib/my_file").
47 """
48
49 shell_rc, out_buf = gc.cmd_fnc_u("which " + file_path, quiet=1,
50 print_output=0, show_err=0)
51 if shell_rc != 0:
52 error_message = "Failed to find complete path for file \"" +\
53 file_path + "\".\n"
54 error_message += gp.sprint_var(shell_rc, 1)
55 error_message += out_buf
56 if robot_env:
57 BuiltIn().fail(gp.sprint_error(error_message))
58 else:
59 gp.print_error_report(error_message)
60 return False
61
62 file_path = out_buf.rstrip("\n")
63
64 return file_path
65
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060066
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060067def dft(value, default):
68
69 r"""
70 Return default if value is None. Otherwise, return value.
71
72 This is really just shorthand as shown below.
73
74 dft(value, default)
75
76 vs
77
78 default if value is None else value
79
80 Description of arguments:
81 value The value to be returned.
82 default The default value to return if value is
83 None.
84 """
85
86 return default if value is None else value
87
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060088
Michael Walsh0f2ea5f2017-02-20 15:55:00 -060089def get_mod_global(var_name,
90 default=None,
91 mod_name="__main__"):
92
93 r"""
94 Get module global variable value and return it.
95
96 If we are running in a robot environment, the behavior will default to
97 calling get_variable_value.
98
99 Description of arguments:
100 var_name The name of the variable whose value is
101 sought.
102 default The value to return if the global does not
103 exist.
104 mod_name The name of the module containing the
105 global variable.
106 """
107
108 if robot_env:
109 return BuiltIn().get_variable_value("${" + var_name + "}", default)
110
111 try:
112 module = sys.modules[mod_name]
113 except KeyError:
114 gp.print_error_report("Programmer error - The mod_name passed to" +
115 " this function is invalid:\n" +
116 gp.sprint_var(mod_name))
117 raise ValueError('Programmer error.')
118
119 if default is None:
120 return getattr(module, var_name)
121 else:
122 return getattr(module, var_name, default)
123
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600124
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600125def global_default(var_value,
126 default=0):
127
128 r"""
129 If var_value is not None, return it. Otherwise, return the global
130 variable of the same name, if it exists. If not, return default.
131
132 This is meant for use by functions needing help assigning dynamic default
133 values to their parms. Example:
134
135 def func1(parm1=None):
136
137 parm1 = global_default(parm1, 0)
138
139 Description of arguments:
140 var_value The value being evaluated.
141 default The value to be returned if var_value is
142 None AND the global variable of the same
143 name does not exist.
144 """
145
146 var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
147
148 return dft(var_value, get_mod_global(var_name, 0))
Michael Walsh7db77942017-01-10 11:37:06 -0600149
Michael Walsh7db77942017-01-10 11:37:06 -0600150
Michael Walsh7db77942017-01-10 11:37:06 -0600151def set_mod_global(var_value,
152 mod_name="__main__",
153 var_name=None):
154
155 r"""
156 Set a global variable for a given module.
157
158 Description of arguments:
159 var_value The value to set in the variable.
160 mod_name The name of the module whose variable is
161 to be set.
162 var_name The name of the variable to set. This
163 defaults to the name of the variable used
164 for var_value when calling this function.
165 """
166
167 try:
168 module = sys.modules[mod_name]
169 except KeyError:
170 gp.print_error_report("Programmer error - The mod_name passed to" +
171 " this function is invalid:\n" +
172 gp.sprint_var(mod_name))
173 raise ValueError('Programmer error.')
174
175 if var_name is None:
176 var_name = gp.get_arg_name(None, 1, 2)
177
178 setattr(module, var_name, var_value)
179
Michael Walsh7db77942017-01-10 11:37:06 -0600180
Michael Walshde791732016-09-06 14:25:24 -0500181def my_parm_file(prop_file_path):
182
183 r"""
184 Read a properties file, put the keys/values into a dictionary and return
185 the dictionary.
186
187 The properties file must have the following format:
188 var_name<= or :>var_value
189 Comment lines (those beginning with a "#") and blank lines are allowed and
190 will be ignored. Leading and trailing single or double quotes will be
191 stripped from the value. E.g.
192 var1="This one"
193 Quotes are stripped so the resulting value for var1 is:
194 This one
195
196 Description of arguments:
Michael Walsh7423c012016-10-04 10:27:21 -0500197 prop_file_path The caller should pass the path to the
198 properties file.
Michael Walshde791732016-09-06 14:25:24 -0500199 """
200
201 # ConfigParser expects at least one section header in the file (or you
202 # get ConfigParser.MissingSectionHeaderError). Properties files don't
203 # need those so I'll write a dummy section header.
204
205 string_file = StringIO.StringIO()
206 # Write the dummy section header to the string file.
207 string_file.write('[dummysection]\n')
208 # Write the entire contents of the properties file to the string file.
209 string_file.write(open(prop_file_path).read())
210 # Rewind the string file.
211 string_file.seek(0, os.SEEK_SET)
212
213 # Create the ConfigParser object.
214 config_parser = ConfigParser.ConfigParser()
215 # Make the property names case-sensitive.
216 config_parser.optionxform = str
217 # Read the properties from the string file.
218 config_parser.readfp(string_file)
219 # Return the properties as a dictionary.
220 return dict(config_parser.items('dummysection'))
221
Michael Walsh7423c012016-10-04 10:27:21 -0500222
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600223def file_to_list(file_path,
224 newlines=0,
225 comments=1,
226 trim=0):
227
228 r"""
229 Return the contents of a file as a list. Each element of the resulting
230 list is one line from the file.
231
232 Description of arguments:
233 file_path The path to the file (relative or
234 absolute).
235 newlines Include newlines from the file in the
236 results.
237 comments Include comment lines and blank lines in
238 the results. Comment lines are any that
239 begin with 0 or more spaces followed by
240 the pound sign ("#").
241 trim Trim white space from the beginning and
242 end of each line.
243 """
244
245 lines = []
246 file = open(file_path)
247 for line in file:
248 if not comments:
249 if re.match(r"[ ]*#|^$", line):
250 continue
251 if not newlines:
252 line = line.rstrip("\n")
253 if trim:
254 line = line.strip()
255 lines.append(line)
256
257 return lines
258
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600259
Michael Walsh7423c012016-10-04 10:27:21 -0500260def return_path_list():
261
262 r"""
263 This function will split the PATH environment variable into a PATH_LIST
264 and return it. Each element in the list will be normalized and have a
265 trailing slash added.
266 """
267
268 PATH_LIST = os.environ['PATH'].split(":")
269 PATH_LIST = [os.path.normpath(path) + os.sep for path in PATH_LIST]
270
271 return PATH_LIST
272
Michael Walsh7db77942017-01-10 11:37:06 -0600273
Michael Walsh9fac55c2017-09-29 16:53:56 -0500274def escape_bash_quotes(buffer):
275
276 r"""
277 Escape quotes in string and return it.
278
279 The escape style implemented will be for use on the bash command line.
280
281 Example:
282 That's all.
283
284 Result:
285 That'\''s all.
286
287 The result may then be single quoted on a bash command. Example:
288
289 echo 'That'\''s all.'
290
291 Description of argument(s):
292 buffer The string whose quotes are to be escaped.
293 """
294
295 return re.sub("\'", "\'\\\'\'", buffer)
296
297
Michael Walsh7db77942017-01-10 11:37:06 -0600298def quote_bash_parm(parm):
299
300 r"""
301 Return the bash command line parm with single quotes if they are needed.
302
303 Description of arguments:
304 parm The string to be quoted.
305 """
306
307 # If any of these characters are found in the parm string, then the
308 # string should be quoted. This list is by no means complete and should
309 # be expanded as needed by the developer of this function.
310 bash_special_chars = set(' $')
311
312 if any((char in bash_special_chars) for char in parm):
313 return "'" + parm + "'"
314
315 return parm
316
Michael Walsh1c85bab2017-05-04 14:29:24 -0500317
Michael Walshf74b3e42018-01-10 11:11:54 -0600318def get_host_name_ip(host,
319 short_name=0):
Michael Walsh1c85bab2017-05-04 14:29:24 -0500320
321 r"""
322 Get the host name and the IP address for the given host and return them as
323 a tuple.
324
325 Description of argument(s):
Michael Walshd1b6c702017-05-30 17:54:30 -0500326 host The host name or IP address to be obtained.
Michael Walshf74b3e42018-01-10 11:11:54 -0600327 short_name Include the short host name in the
328 returned tuple, i.e. return host, ip and
329 short_host.
Michael Walsh1c85bab2017-05-04 14:29:24 -0500330 """
331
Michael Walshf74b3e42018-01-10 11:11:54 -0600332 host_name = socket.getfqdn(host)
Michael Walshd1b6c702017-05-30 17:54:30 -0500333 try:
334 host_ip = socket.gethostbyname(host)
335 except socket.gaierror as my_gaierror:
336 message = "Unable to obtain the host name for the following host:" +\
337 "\n" + gp.sprint_var(host)
338 gp.print_error_report(message)
339 raise my_gaierror
Michael Walsh1c85bab2017-05-04 14:29:24 -0500340
Michael Walshf74b3e42018-01-10 11:11:54 -0600341 if short_name:
342 host_short_name = host_name.split(".")[0]
343 return host_name, host_ip, host_short_name
344 else:
345 return host_name, host_ip
Michael Walsh1c85bab2017-05-04 14:29:24 -0500346
Michael Walsheaa16852017-09-19 16:30:43 -0500347
348def pid_active(pid):
349
350 r"""
351 Return true if pid represents an active pid and false otherwise.
352
353 Description of argument(s):
354 pid The pid whose status is being sought.
355 """
356
357 try:
358 os.kill(int(pid), 0)
359 except OSError as err:
360 if err.errno == errno.ESRCH:
361 # ESRCH == No such process
362 return False
363 elif err.errno == errno.EPERM:
364 # EPERM clearly means there's a process to deny access to
365 return True
366 else:
367 # According to "man 2 kill" possible error values are
368 # (EINVAL, EPERM, ESRCH)
369 raise
370
371 return True