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