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