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 26 r""" 27 Add a trailing slash to the directory path if it doesn't already have one 28 and return it. 29 30 Description of arguments: 31 dir_path A directory path. 32 """ 33 34 return os.path.normpath(dir_path) + os.path.sep 35 36 37def 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 66 67def 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 88 89def 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 124 125def 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)) 149 150 151def 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 180 181def 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: 197 prop_file_path The caller should pass the path to the 198 properties file. 199 """ 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 222 223def 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 259 260def 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 273 274def 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 298def 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 317 318def get_host_name_ip(host): 319 320 r""" 321 Get the host name and the IP address for the given host and return them as 322 a tuple. 323 324 Description of argument(s): 325 host The host name or IP address to be obtained. 326 """ 327 328 host_host_name = socket.getfqdn(host) 329 try: 330 host_ip = socket.gethostbyname(host) 331 except socket.gaierror as my_gaierror: 332 message = "Unable to obtain the host name for the following host:" +\ 333 "\n" + gp.sprint_var(host) 334 gp.print_error_report(message) 335 raise my_gaierror 336 337 return host_host_name, host_ip 338 339 340def pid_active(pid): 341 342 r""" 343 Return true if pid represents an active pid and false otherwise. 344 345 Description of argument(s): 346 pid The pid whose status is being sought. 347 """ 348 349 try: 350 os.kill(int(pid), 0) 351 except OSError as err: 352 if err.errno == errno.ESRCH: 353 # ESRCH == No such process 354 return False 355 elif err.errno == errno.EPERM: 356 # EPERM clearly means there's a process to deny access to 357 return True 358 else: 359 # According to "man 2 kill" possible error values are 360 # (EINVAL, EPERM, ESRCH) 361 raise 362 363 return True 364