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