Package PyFoam :: Package Applications :: Module CreateModuleFile
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Applications.CreateModuleFile

  1  """ 
  2  Application-class that implements pyFoamCreateModuleFile.py 
  3   
  4  Generate a Modules modulefile for OpenFOAM using differences in environment 
  5  variables before and after sourcing the main OpenFOAM configuration file 
  6   
  7  For more information on Modules, visit the Environment  Modules Project: 
  8  http://modules.sourceforge.net 
  9   
 10  Usage : pyFoamCreateModuleFile.py OpenFOAM_CfgFile moduleFile 
 11   
 12          For example: pyFoamCreateModuleFile.py ./bashrc /tmp/module 
 13   
 14  Warning #1: This command will not work if your OpenFOAM environment variabales are already 
 15              initialized. 
 16   
 17  Warning #2: This command will not work if you are using the superuser account (aka: root) 
 18   
 19  Author: 
 20    Martin Beaudoin, Hydro-Quebec, 2012.  All rights reserved 
 21   
 22  """ 
 23   
 24  import os 
 25  import sys 
 26  import string 
 27  import re 
 28  from optparse import OptionGroup 
 29   
 30  from PyFoamApplication import PyFoamApplication 
 31  from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile 
 32  from PyFoam.Basics.Utilities import execute 
 33  from sets import Set 
 34  from os import path 
 35   
36 -class CreateModuleFile(PyFoamApplication):
37 - def __init__(self,args=None):
38 description=""" 39 Create a Modules modulefile for OpenFOAM. Input parameter 'OpenFOAM configuration file': bashrc or cshrc file for OpenFOAM; usually $WM_PROJECT_DIR/etc/bashrc or $WM_PROJECT_DIR/etc/cshrc. Output parameter 'modulefile': the resulting module file. For more information on Modules, visit the Environment Modules Project: http://http://modules.sourceforge.net 40 """ 41 PyFoamApplication.__init__(self, 42 args=args, 43 description=description, 44 usage="%prog OpenFOAM_cfgFile modulefile", 45 interspersed=True, 46 changeVersion=False, 47 nr=2)
48
49 - def addOptions(self):
50 module=OptionGroup(self.parser, 51 "Module", 52 "Options specific for the module-utility") 53 self.parser.add_option_group(module) 54 55 module.add_option("--csh", 56 action="store_true", 57 dest="useCshell", 58 default=False, 59 help='Use csh instead of bash for activating the OpenFOAM configuration') 60 module.add_option("--clear-environment", 61 action="store_true", 62 dest="clearEnvironment", 63 default=False, 64 help='Attempt to clear the environment of all traces of an OpenFOAM-installation before proceeding. This is no substitute to having a clean environment')
65 66
67 - def uniqifyPathEnvVar(self, pathEnvVar):
68 """Remove all duplicates from PATH env var. Order preserving""" 69 checked = [] 70 for e in pathEnvVar.split(':'): 71 if e not in checked: 72 checked.append(e) 73 74 return string.join(checked, ':')
75
76 - def removeComponentWithSubstrFromPathEnvVar(self, pathEnvVar, removeSubStr):
77 """Remove components from PATH env var where a substring is present. Order preserving""" 78 keepComponents = [] 79 pathComponents = pathEnvVar.split(':') 80 81 for e in pathComponents: 82 if e.find(removeSubStr) < 0: 83 keepComponents.append(e) 84 85 return string.join(keepComponents, ':') 86
87 - def removeComponentFromPathEnvVar(self, pathEnvVar, removePathComponents):
88 """Remove components from PATH env var. Order preserving""" 89 keepComponents = [] 90 pathComponents = pathEnvVar.split(':') 91 removeComponents = removePathComponents.split(':') 92 93 for e in pathComponents: 94 if e not in removeComponents: 95 keepComponents.append(e) 96 97 return string.join(keepComponents, ':') 98 99
100 - def writeModuleFileHeader(self, fid, version):
101 """Write Modules file header""" 102 fid.write("#%Module1.0\n") 103 fid.write("\n") 104 fid.write("proc ModulesHelp { } {\n") 105 fid.write(" puts stderr \"OpenFOAM version " + version + "\"\n") 106 fid.write("}\n") 107 fid.write("\n") 108 fid.write("module-whatis \"OpenFOAM version " + version + "\"\n")
109 110
111 - def writeModuleFileFooter(self, fid):
112 """Write Modules file footer""" 113 fid.write("\n") 114 fid.write("#EOF\n") 115 return
116
117 - def writeModuleEnvironmentEntry(self, fid, envVarDict, homeVar, userVar):
118 """Write Modules file environment variables""" 119 fid.write("\n") 120 fid.write("set HOME \"$env(HOME)\"\n") 121 fid.write("set USER \"$env(USER)\"\n") 122 fid.write("\n") 123 fid.write("# Environment variables\n") 124 125 # Memorize PATH variables 126 pathVars = {} 127 128 #Sorting keys 129 keylist = envVarDict.keys() 130 keylist.sort() 131 for k in keylist: 132 value = envVarDict[k][0] 133 134 # Remove expanded occurences of $HOME variable 135 value = value.replace(homeVar, "$HOME") 136 137 # Remove expanded occurences of $USER variable 138 value = value.replace(userVar, "$USER") 139 140 if k.find('PATH') > -1 and value != ":": 141 pathVars[k] = value 142 else: 143 fid.write("setenv " + k + " " + "\"" + value + "\""+ "\n") 144 145 # Prepend PATH variables 146 fid.write("\n") 147 fid.write("# Various PATH variables\n") 148 for k in pathVars: 149 value = pathVars[k] 150 if len(value) > 0: 151 fid.write("prepend-path " + k + " " + "\"" + pathVars[k] + "\""+ "\n") 152 fid.write("\n") 153 154 # Write TCL variables for the environment variables. 155 # This is only necessary for module. 156 # The aliases definitions will use this 157 # We also need to pay attention to empty environment variables 158 # for TCL. if [info exists env(VARNAME)] {set value $env(VARNAME)} 159 # 160 fid.write("# Temporary TCL variables for the environment variables\n") 161 fid.write("# Module will need this for the aliases when parsing this file\n") 162 for k in keylist: 163 fid.write("if [info exists env(" + k + ")] {set " + k + ' \"$env(' + k + ')\"}\n') 164 fid.write("\n")
165 166
167 - def writeModuleAliasEntry(self, fid, aliasesVarDict, homeVar, userVar):
168 """Write Modules file aliases""" 169 fid.write("# Aliases\n") 170 171 #Sorting keys 172 keylist = aliasesVarDict.keys() 173 keylist.sort() 174 for k in keylist: 175 value = aliasesVarDict[k][0] 176 177 # Remove expanded occurences of $HOME variable 178 value = value.replace(homeVar, "$HOME") 179 180 # Remove expanded occurences of $USER variable 181 value = value.replace(userVar, "$USER") 182 183 fid.write("set-alias " + k + " " + "\"" + value + "\""+ "\n")
184
185 - def run(self):
186 cfgFile=self.parser.getArgs()[0] 187 moduleFile=self.parser.getArgs()[1] 188 useCsh = self.opts.useCshell 189 190 if self.opts.clearEnvironment: 191 self.warning("Clearing environment of variables that might come from an OpenFAOM-installation. Nevertheless it is preferable to use a clean environment") 192 try: 193 oldVersion=os.environ["WM_PROJECT_VERSION"] 194 except KeyError: 195 self.warning("Seems to be a clean environment anyway") 196 oldVersion=None 197 198 if oldVersion: 199 for e in os.environ.keys(): 200 for p in ["WM_","FOAM_"]: 201 if e.find(p)==0: 202 del os.environ[e] 203 break 204 for p in ["PATH","DYLD_LIBRARY_PATH","LD_LIBRARY_PATH","MANPATH","PV_PLUGIN_PATH"]: 205 if p in os.environ: 206 lst=os.environ[p].split(":") 207 os.environ[p]=":".join([l for l in lst if l.find(oldVersion)<0]) 208 209 if path.exists(cfgFile) and path.isfile(cfgFile) and os.access(cfgFile, os.R_OK): 210 print " Using file " + cfgFile + " for loading the OpenFOAM environment" 211 212 # Some more sanity check 213 fileData = open(cfgFile).read() 214 if not useCsh and "setenv" in fileData: 215 self.error(" Error: Detecting 'setenv' instructions in this bash file. Please provide a configuration file compatible for bash, or use the --csh option.") 216 elif useCsh and "export" in fileData: 217 self.error(" Error: Detecting 'export' instructions in this csh file. Please provide a configuration file compatible for csh.") 218 else: 219 print " The configuration file seems ok" 220 else: 221 self.error(" Error: Cannot access file: " + cfgFile) 222 223 # We choose not to run if the OpenFOAM environment is already loaded. 224 # We obviously cannot diff from such an environment 225 if os.getenv("WM_PROJECT") != None: 226 self.error(""" Error: Cannot run with OpenFOAM environment variables already present 227 You need to run this script from a clean environment""") 228 229 # We choose not to run under the user 'root', simply because the HOME and USER environment 230 # variables are usually very similar for this user, and this will cause problem later on 231 # For instance, under Centos, for the super user: 232 # HOME=/root 233 # USER=root 234 # Those two are very similar 235 if os.getenv("USER") == "root": 236 self.error(""" Error: You should not run this script from the 'root' account. 237 Please invoke this pyFoam command from a plain OpenFOAM user account. 238 Then, make the result file available to the super user (root) of the" 239 destination host in order to install the modules configuration files.""") 240 241 # Grab environment + aliases before the activation of OpenFOAM 242 # We start from a minimal environment using 'env -i' 243 shellCmd = 'bash -c' 244 sourceCmd = '.' 245 246 if useCsh: 247 shellCmd = 'csh -c' 248 sourceCmd = 'source' 249 250 oldEnv=Set(execute(shellCmd + ' "env|sort"')) 251 oldAliases=Set(execute(shellCmd + ' "alias|sort"')) 252 253 # Grab environment + aliases after the activation of OpenFOAM 254 newEnv=Set(execute(shellCmd + ' \"' + sourceCmd + ' ' + cfgFile + '; env|sort"')) 255 newAliases=Set(execute(shellCmd + ' \"' + sourceCmd + ' ' + cfgFile + '; alias|sort"')) 256 257 # Handling of environment variables 258 # Memorize all the PATH environment variables for later processing 259 oldPath = {} 260 newPath = {} 261 homeVar = "" 262 userVar = "" 263 264 for v in oldEnv: 265 if v.find('=') > -1: 266 key, value = v.split('=', 1) 267 268 # Memorize PATH variables 269 if key.find('PATH') > -1: 270 oldPath[key] = value.replace('\n', '') 271 272 # We remove any reference to PyFOAM in the old PATH env. variable 273 # Since we run this script with PyFOAM, environment variables for PyFoam are 274 # present in oldPath. If the configuration file for OpenFOAM requires PyFoam too, 275 # we risk to lose these variables because they will be in common in both the 276 # 'before' and 'after'environment. 277 # This is ugly, but PyFOAM is just too useful to write this script with plain 278 # python. 279 # If you have installed PyFoam under a path where the string 'PyFoam' is not present, 280 # you will simply have to manually add the necessary PyFoam environment variables 281 # yourself in the module file. No biggie, 282 oldPath[key] = self.removeComponentWithSubstrFromPathEnvVar(oldPath[key], 'PyFoam') 283 284 # Memorize HOME variable 285 if key == 'HOME': 286 homeVar = value.replace('\n', '') 287 288 # Memorize USER variable 289 if key == 'USER': 290 userVar = value.replace('\n', '') 291 292 # Using sets, it is trivial to remove common environment variables 293 # and aliases between the two environments 294 moduleEnv=newEnv - oldEnv 295 moduleAliases=newAliases - oldAliases 296 297 # Dictionary for environment variables 298 envVar = {} 299 300 # Dictionary for aliases 301 aliasesVar = {} 302 303 # Iterate through environment variables and store in dictionary 304 for v in moduleEnv: 305 if v.find('=') > -1: 306 key, value = v.split('=') 307 308 # Minor cleanup 309 value = value.replace('\n', '') 310 311 # Memorize PATH variables for later processing 312 if key.find('PATH') > -1: 313 newPath[key] = value 314 else: 315 envVar.setdefault(key, []).append(value) 316 317 # Handle the PATH variables 318 for v in newPath: 319 if v in oldPath: 320 # Cleanup old PATH components 321 newPath[v] = self.removeComponentFromPathEnvVar(newPath[v], oldPath[v]) 322 323 # Remove duplicate entries in PATH variable 324 newPath[v] = self.uniqifyPathEnvVar(newPath[v]) 325 envVar.setdefault(v, []).append(newPath[v]) 326 327 # Iterate through aliases variables and store them in dictionary 328 for v in moduleAliases: 329 if v.find('=') > -1: 330 key, value = v.split('=', 1) 331 332 # Minor cleanup 333 key = key.replace("alias ", "") 334 value = value.replace('\n', "") 335 value = value.replace('\'', "") 336 aliasesVar.setdefault(key, []).append(value) 337 338 # Generate module entries 339 print " Generating modulefile: " , moduleFile 340 341 f = open(moduleFile, 'w') 342 343 self.writeModuleFileHeader(f, envVar["WM_PROJECT_VERSION"][0]) 344 self.writeModuleEnvironmentEntry(f, envVar, homeVar, userVar) 345 self.writeModuleAliasEntry(f, aliasesVar, homeVar, userVar) 346 self.writeModuleFileFooter(f) 347 348 f.close() 349 print " Done\n"
350