# ICE Revision: $Id$
"""Getting Information about the Foam-Installation (like the installation directory)"""
from os import environ,path,listdir
import sys
if sys.version_info<(2,6):
from popen2 import popen4
else:
from subprocess import Popen,PIPE,STDOUT
import re
from PyFoam.Error import error,warning
from PyFoam import configuration as config
[docs]def getPathFromEnviron(name):
"""Gets a path from an environment variable
:return: the path
:rtype: string
:param name: the name of the environment variable"""
tmp=""
if name in environ:
tmp=path.normpath(environ[name])
return tmp
[docs]def foamTutorials():
""":return: directory in which the tutorials reside"""
return getPathFromEnviron("FOAM_TUTORIALS")
[docs]def foamEtc():
""":return: the etc-directory of the distro"""
return path.join(getPathFromEnviron("WM_PROJECT_DIR"),"etc")
[docs]def foamCaseDicts():
""":return: the caseDicts-directory of the distro"""
return path.join(foamEtc(),"caseDicts")
[docs]def foamPostProcessing():
""":return: the caseDicts/postProcessing-directory of the distro"""
return path.join(foamCaseDicts(),"postProcessing")
[docs]def foamMPI():
""":return: the used MPI-Implementation"""
if "WM_MPLIB" not in environ:
return ()
else:
vStr=environ["WM_MPLIB"]
return vStr
[docs]def foamVersionString(useConfigurationIfNoInstallation=False):
""":return: string for the Foam-version as found
in $WM_PROJECT_VERSION"""
if "WM_PROJECT_VERSION" not in environ and not useConfigurationIfNoInstallation:
return ""
else:
if "WM_PROJECT_VERSION" in environ:
vStr=environ["WM_PROJECT_VERSION"]
else:
vStr=""
if vStr=="" and useConfigurationIfNoInstallation:
vStr=config().get("OpenFOAM","Version")
return vStr
[docs]class VersionTuple(tuple):
"""Wrapper around the regular tuple that is printed in a way that
can be parsed as a tuple in a OF-dictionary
"""
# Python3 doesn't like this. But it was only here out of courtesy
# def __init__(self,data):
# tuple.__init__(self,data)
def __str__(self):
return ".".join([str(e) for e in self])
[docs]def foamVersion(useConfigurationIfNoInstallation=False):
""":return: tuple that represents the Foam-version as found
in $WM_PROJECT_VERSION"""
vStr=foamVersionString(useConfigurationIfNoInstallation=useConfigurationIfNoInstallation)
if len(vStr)>0 and vStr[0]=="v":
vStr=vStr[1:]
if vStr[-1]=="+":
vStr=vStr[:-1]
if vStr=="":
return ()
else:
res=[]
for el in vStr.split("."):
for e in el.split("-"):
try:
res.append(int(e))
except:
res.append(e)
return VersionTuple(res)
[docs]def foamVersionNumber(useConfigurationIfNoInstallation=False):
""":return: tuple that represents the Foam-Version-Number (without
strings"""
ver=foamVersion(useConfigurationIfNoInstallation=useConfigurationIfNoInstallation)
if ver==("dev",) or ver==("plus",):
return VersionTuple((9,9,9))
nr=[]
for e in ver:
if type(e)==int:
nr.append(e)
else:
break
return VersionTuple(nr)
[docs]def oldAppConvention():
"""Returns true if the version of OpenFOAM is older than 1.5 and
it therefor uses the 'old' convention to call utilities ("dot, case")
"""
return foamVersionNumber()>() and foamVersionNumber()<(1,5)
[docs]def oldTutorialStructure():
"""Returns true if the version of OpenFOAM is older than 1.6 and
it therefor uses the 'old' (flat) structure for the tutorials
"""
return foamVersionNumber()>() and foamVersionNumber()<(1,6)
[docs]def installationPath():
"""Path to the installation"""
return path.abspath(environ["WM_PROJECT_DIR"])
[docs]def findInstalledVersions(basedir,valid,forkName="openfoam"):
versions={}
basedir=path.abspath(basedir)
try:
candidates=listdir(basedir)
except OSError:
return versions
for f in candidates:
m=valid.match(f)
if m:
dname=path.join(basedir,f)
if path.isdir(dname):
name=m.groups(1)[0]
dotDir=path.join(dname,".OpenFOAM-"+name)
etcDir=path.join(dname,"etc")
if path.isdir(etcDir) and path.exists(path.join(etcDir,"bashrc")):
versions[(forkName,m.groups(1)[0])]=dname
elif path.isdir(dotDir) and path.exists(path.join(dotDir,"bashrc")):
versions[(forkName,m.groups(1)[0])]=dname
return versions
__foamInstallations=None
[docs]def findInstallationDir(newVersion):
installed=foamInstalledVersions()
found=[]
for fork,version in installed.keys():
if newVersion==version:
found.append((fork,version))
elif newVersion==(fork+"-"+version):
found.append((fork,version))
if len(found)==0:
error("Can't find basedir for OpenFOAM-version", newVersion, "in",
", ".join([ a[0]+"-"+a[1] for a in installed.keys() ]))
elif len(found)==1:
return found[0][0],found[0][1],installed[found[0]]
else:
error("Requested version:",newVersion,"Matches found:",
", ".join([ a[0]+"-"+a[1] for a in found ]))
[docs]def findThirdPartyDir(newVersion):
if isinstance(newVersion,tuple):
newVersion = "{}-{}".format(*newVersion)
fork, version, installation = findInstallationDir(newVersion)
thirdPartyDir = path.join(installation,
path.pardir,
"ThirdParty-{}".format(version))
if path.isdir(thirdPartyDir):
return thirdPartyDir
else:
return None
[docs]def foamInstalledVersions():
""":return: A list with the installed versions of OpenFOAM"""
global __foamInstallations
if __foamInstallations:
return __foamInstallations
__foamInstallations={}
forks=config().getList("OpenFOAM","Forks")
for fork in forks:
currentFork=foamFork()
if "WM_PROJECT_INST_DIR" in environ and currentFork==fork:
basedir=environ["WM_PROJECT_INST_DIR"]
else:
basedir=path.expanduser(config().get("OpenFOAM","Installation-"+fork))
if not path.exists(basedir) or not path.isdir(basedir):
warning("Basedir",basedir,"for fork",fork,"does not exist or is not a directory")
# continue
for bdir in [basedir]+config().getList("OpenFOAM","AdditionalInstallation-"+fork):
for val in [re.compile(s) for s in config().getList("OpenFOAM","DirPatterns-"+fork)]:
__foamInstallations.update(findInstalledVersions(bdir,val,fork))
return __foamInstallations
[docs]def foamFork():
"""The currently used fork of OpenFOAM/Foam"""
try:
return environ["WM_FORK"]
except KeyError:
vStr=foamVersionString()
if (len(vStr)>1 and vStr[0]=="v") or vStr=="com":
return "openfoamplus"
else:
return "openfoam"
[docs]def ensureDynamicLibraries():
"""Ensure that the dynamic library path is set for systems where it
was erased for security rasons (for instance Mac OS X 10.11)"""
def makeLdPath():
pth=[environ[p] for p in ["FOAM_LIBBIN",
"FOAM_USER_LIBBIN",
"FOAM_SITE_LIBBIN"] if p in environ]
if "FOAM_MPI" in environ and "FOAM_LIBBIN" in environ:
pth=[path.join(environ["FOAM_LIBBIN"],environ["FOAM_MPI"])]+pth
return pth
if sys.platform in ["darwin"]:
if "DYLD_LIBRARY_PATH" not in environ:
environ["DYLD_LIBRARY_PATH"]=":".join(makeLdPath())
if "LD_LIBRARY_PATH" not in environ:
environ["LD_LIBRARY_PATH"]=":".join(makeLdPath())
[docs]def shellExecutionPrefix(ensureDynamic=True,asList=False):
"""Stuff to prefix to a call that is passed to the shell. Main
application is currently to work around a security feature of Mac OS X
10.11 that doesn't pass the load paths for the dynamic libraries to a
shell"""
if ensureDynamic:
ensureDynamicLibraries()
prefix=[]
if sys.platform in ["darwin"]:
for v in ["LD_LIBRARY_PATH","DYLD_LIBRARY_PATH"]:
if v in environ:
prefix.append("export "+v+"="+environ[v]+"; ")
if asList:
return prefix
else:
return "".join(prefix)
[docs]def changeFoamVersion(new,
force64=False,
force32=False,
compileOption=None,
foamCompiler=None,
wmCompiler=None):
"""Changes the used FoamVersion. Only valid during the runtime of
the interpreter (the script or the Python session)
:param new: The new Version
:param force64: Forces the 64-bit-version to be chosen
:param force32: Forces the 32-bit-version to be chosen
:param compileOption: Forces Debug or Opt
:param wmCompiler: Force new value for WM_COMPILER
:param foamCompiler: Force system or OpenFOAM-Compiler"""
newFork,newVersion,basedir=findInstallationDir(new)
old=None
oldFork=foamFork()
if "WM_PROJECT_VERSION" in environ:
old=environ["WM_PROJECT_VERSION"]
if newVersion==old and newFork==oldFork:
warning(old+"-"+foamFork(),"is already being used")
else:
warning("No OpenFOAM-Version installed")
if path.exists(path.join(basedir,"etc")):
script=path.join(basedir,"etc","bashrc")
else:
script=path.join(basedir,".OpenFOAM-"+new,"bashrc")
forceArchOption=None
if force64:
forceArchOption="64"
elif force32:
forceArchOption="32"
injectVariables(script,
forceArchOption=forceArchOption,
compileOption=compileOption,
foamCompiler=foamCompiler,
wmCompiler=wmCompiler)
try:
if old==environ["WM_PROJECT_VERSION"] and oldFork==foamFork():
warning("Problem while changing to version",new,"old version still used:",foamFork()+"-"+environ["WM_PROJECT_VERSION"])
except KeyError:
pass
[docs]def injectVariables(script,
forceArchOption=None,
compileOption=None,
foamCompiler=None,
wmCompiler=None):
"""Executes a script in a subshell and changes the current
environment with the enivironment after the execution
:param script: the script that is executed
:param forceArchOption: To which architecture Option should be forced
:param compileOption: to which value the WM_COMPILE_OPTION should be forced
:param wmCompiler: Force new value for WM_COMPILER
:param foamCompiler: Force system or OpenFOAM-Compiler"""
# Certan bashrc-s fail if these are set
for v in ["FOAM_INST_DIR",
"WM_THIRD_PARTY_DIR",
"WM_PROJECT_USER_DIR",
"OPAL_PREFIX"]:
try:
del environ[v]
except KeyError:
pass
if not path.exists(script):
error("Can not execute",script,"it does not exist")
try:
if "SHELL" in environ:
shell=environ["SHELL"]
if(path.basename(shell).find("python")==0):
# this assumes that the 'shell' is a PyFoam-Script on a cluster
shell=config().get("Paths","bash")
environ["SHELL"]=shell
allowedShells = [ "bash", "zsh", "sh", "dash"]
if not path.basename(shell) in allowedShells:
error("Currently only implemented for the shells",allowedShells,", not for",shell)
cmd=""
postCmd=""
if forceArchOption!=None:
cmd+="export WM_ARCH_OPTION="+forceArchOption+"; "
postCmd+=" WM_ARCH_OPTION="+forceArchOption
if compileOption!=None:
cmd+="export WM_COMPILE_OPTION="+compileOption+"; "
postCmd+=" WM_COMPILE_OPTION="+compileOption
if foamCompiler!=None:
cmd+="export foamCompiler="+foamCompiler+"; "
postCmd+=" foamCompiler="+foamCompiler
if wmCompiler!=None:
cmd+="export WM_COMPILER="+wmCompiler+"; "
postCmd+=" WM_COMPILER="+wmCompiler
cmd+=" . "+script+postCmd+'; echo "Starting The Dump Of Variables"; export'
except KeyError:
# Instead of 'KeyError as name'. This is compatible with 2.4-3.2
# http://docs.pythonsprints.com/python3_porting/py-porting.html#handling-exceptions
name = sys.exc_info()[1]
error("Can't do it, because shell variable",name,"is undefined")
if sys.version_info<(2,6):
raus,rein = popen4(cmd)
else:
p = Popen("bash -c '"+cmd+"'", shell=True,
stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(rein,raus)=(p.stdin,p.stdout)
lines=[l.strip().decode() for l in raus.readlines()]
rein.close()
raus.close()
# clumsy but avoids more complicated expressions
exp=re.compile('export (.+)="(.*)"$')
exp2=re.compile("export (.+)='(.*)'$")
exp3=re.compile('declare -x (.+)="(.*)"$')
cnt=0
for l in lines:
m=exp.match(str(l))
if not m:
m=exp2.match(str(l))
if not m:
m=exp3.match(str(l))
if m:
cnt+=1
environ[m.groups()[0]]=m.groups()[1]
[docs]def getUserName():
"""Get the current username"""
import getpass
return getpass.getuser()
[docs]def getPublicKey():
from PyFoam.Infrastructure.Authentication import myPublicKeyText,ensureKeyPair
ensureKeyPair()
return myPublicKeyText()
[docs]def getAuthenticatedKeys():
from PyFoam.Infrastructure.Authentication import authenticatedKeys,ensureKeyPair
ensureKeyPair()
return authenticatedKeys()
[docs]def getUserTempDir():
"""Return path to a user-specific private directory. Create directory if not existing"""
from os import path
import tempfile,os
tempDir=path.join(tempfile.gettempdir(),
"PyFoam_"+getUserName())
if not path.isdir(tempDir):
try:
os.mkdir(tempDir)
except OSError:
tempDir=tempfile.gettempdir()
return tempDir
# Should work with Python3 and Python2