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 quote_bash_parm(parm): 278 279 r""" 280 Return the bash command line parm with single quotes if they are needed. 281 282 Description of arguments: 283 parm The string to be quoted. 284 """ 285 286 # If any of these characters are found in the parm string, then the 287 # string should be quoted. This list is by no means complete and should 288 # be expanded as needed by the developer of this function. 289 bash_special_chars = set(' $') 290 291 if any((char in bash_special_chars) for char in parm): 292 return "'" + parm + "'" 293 294 return parm 295 296 297def get_host_name_ip(host): 298 299 r""" 300 Get the host name and the IP address for the given host and return them as 301 a tuple. 302 303 Description of argument(s): 304 host The host name or IP address to be obtained. 305 """ 306 307 host_host_name = socket.getfqdn(host) 308 try: 309 host_ip = socket.gethostbyname(host) 310 except socket.gaierror as my_gaierror: 311 message = "Unable to obtain the host name for the following host:" +\ 312 "\n" + gp.sprint_var(host) 313 gp.print_error_report(message) 314 raise my_gaierror 315 316 return host_host_name, host_ip 317 318 319def pid_active(pid): 320 321 r""" 322 Return true if pid represents an active pid and false otherwise. 323 324 Description of argument(s): 325 pid The pid whose status is being sought. 326 """ 327 328 try: 329 os.kill(int(pid), 0) 330 except OSError as err: 331 if err.errno == errno.ESRCH: 332 # ESRCH == No such process 333 return False 334 elif err.errno == errno.EPERM: 335 # EPERM clearly means there's a process to deny access to 336 return True 337 else: 338 # According to "man 2 kill" possible error values are 339 # (EINVAL, EPERM, ESRCH) 340 raise 341 342 return True 343