Compilation fix
[foam-extend-3.2.git] / etc / getVariables.py
blob248f9862ee3c5a4b0db2efca1ca8c757653af83a
1 #! /usr/bin/env python
3 # This file sources the etc bashrc, finds the differences to the old
4 # configuration and makes them available in a format that the calling
5 # shell can understand
8 import sys
10 # This part is lifted from six.py (https://pythonhosted.org/six/) to
11 # make sure that this script runs with Python 2 and Python 3
13 # True if we are running on Python 3.
14 PY3 = sys.version_info[0] == 3
16 if PY3:
17 import builtins
18 print_ = getattr(builtins, "print")
19 del builtins
20 else:
21 def print_(*args, **kwargs):
22 """The new-style print function."""
23 fp = kwargs.pop("file", sys.stdout)
24 if fp is None:
25 return
26 def write(data):
27 if not isinstance(data, basestring):
28 data = str(data)
29 fp.write(data)
30 want_unicode = False
31 sep = kwargs.pop("sep", None)
32 if sep is not None:
33 if isinstance(sep, unicode):
34 want_unicode = True
35 elif not isinstance(sep, str):
36 raise TypeError("sep must be None or a string")
37 end = kwargs.pop("end", None)
38 if end is not None:
39 if isinstance(end, unicode):
40 want_unicode = True
41 elif not isinstance(end, str):
42 raise TypeError("end must be None or a string")
43 if kwargs:
44 raise TypeError("invalid keyword arguments to print()")
45 if not want_unicode:
46 for arg in args:
47 if isinstance(arg, unicode):
48 want_unicode = True
49 break
50 if want_unicode:
51 newline = unicode("\n")
52 space = unicode(" ")
53 else:
54 newline = "\n"
55 space = " "
56 if sep is None:
57 sep = space
58 if end is None:
59 end = newline
60 for i, arg in enumerate(args):
61 if i:
62 write(sep)
63 write(arg)
64 write(end)
66 def printDebug(*args):
67 print_(*args,file=sys.stderr)
69 # the actual work starts here
70 from os import environ,path
72 if sys.version_info<(2,6):
73 from popen2 import popen4
74 else:
75 from subprocess import Popen,PIPE,STDOUT
77 # only for development
78 verbose="FOAM_NEW_STARTUP_DEBUG" in environ
80 # Location of this script
81 here=path.dirname(path.abspath(sys.argv[0]))
82 if verbose:
83 printDebug("Using scripts in",here)
85 # For which shell
86 destShell=sys.argv[1]
88 # Variables like WM_COMPILER=Gcc46
89 additional=sys.argv[2:]
91 if verbose:
92 printDebug("Target shell",destShell)
93 printDebug("Additional settings:",additional)
95 # Certain bashrc-s fail if these are set
96 for v in ["FOAM_INST_DIR",
97 "WM_THIRD_PARTY_DIR",
98 "WM_PROJECT_USER_DIR",
99 "OPAL_PREFIX"]:
100 try:
101 del environ[v]
102 except KeyError:
103 pass
105 # To be executed in bash
106 cmd ='echo "=== Export pre";export;echo "=== Alias pre";alias;'
107 cmd+='echo "=== Script";. '+path.join(here,"bashrc")+' '+' '.join(additional)+';'
108 cmd+='echo "=== Export post";export;echo "=== Alias post";alias;'
109 cmd+='echo "=== End"'
111 cmd="bash -c '"+cmd+"'"
113 if verbose:
114 printDebug("Cmd:",cmd)
116 # Execute the shell commands
117 if sys.version_info<(2,6):
118 # for old machines (RHEL 5)
119 raus,rein = popen4(cmd)
120 ret=0 # standin for a proper implementation
121 else:
122 p = Popen(cmd, shell=True,
123 stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
124 (rein,raus)=(p.stdin,p.stdout)
125 ret=p.wait()
127 lines=[l.strip().decode() for l in raus.readlines()]
128 rein.close()
129 raus.close()
131 if verbose or ret!=0:
132 printDebug("========= Script output start")
133 for l in lines:
134 printDebug(l)
135 printDebug("========= Script output end")
137 if ret!=0:
138 printDebug("Command return code",ret,". There seems to be a problem")
140 def extractVariables(lines):
141 vars={}
142 # different forms if bash is called as sh
143 prefixes=["export ","declare -x "]
144 for l in lines:
145 pref=None
146 for p in prefixes:
147 if l.find(p)==0:
148 pref=p
149 break
150 pos=l.find("=")
151 name=l[len(pref):pos]
152 if pos>0:
153 val=l[pos+1:]
154 if val[0]=='"' and val[-1]=='"':
155 val=val[1:-1]
156 else:
157 val=""
158 vars[name]=val
160 return vars
162 def extractAliases(lines):
163 aliases={}
164 for l in lines:
165 pref="" # if called as sh
166 if l.find("alias ")==0:
167 pref="alias "
168 pos=l.find("=")
169 aliases[l[len(pref):pos]]=l[pos+2:-1]
171 return aliases
173 def changedVars(old,new):
174 changed={}
175 for k in new:
176 if k not in old:
177 changed[k]=new[k]
178 elif old[k]!=new[k]:
179 changed[k]=new[k]
180 return changed
182 def splitPaths(orig):
183 new={}
184 for k in orig.keys():
185 if k.find("PATH")>=0 and orig[k].find(":")>=0:
186 new[k]=orig[k].split(":")
187 else:
188 new[k]=orig[k]
189 return new
191 try:
192 vars=splitPaths(
193 changedVars(extractVariables(lines[lines.index("=== Export pre")+1:
194 lines.index("=== Alias pre")]),
195 extractVariables(lines[lines.index("=== Export post")+1:
196 lines.index("=== Alias post")])))
197 aliases=changedVars(extractAliases(lines[lines.index("=== Alias post")+1:
198 lines.index("=== Script")]),
199 extractAliases(lines[lines.index("=== Alias post")+1:
200 lines.index("=== End")]))
202 scriptOutput=lines[lines.index("=== Script")+1:
203 lines.index("=== Export post")]
204 except Exception:
205 e = sys.exc_info()[1] # Needed because python 2.5 does not support 'as e'
206 err, detail, tb = sys.exc_info()
207 printDebug("Output of",cmd,"not successfully parsed")
208 import traceback
209 traceback.print_exception(err,detail,tb,file=sys.stderr)
210 sys.exit(-1)
212 # Pass output of the script to stderr for debugging
213 if len(scriptOutput)>0:
214 for l in scriptOutput:
215 print_(l,file=sys.stderr)
217 class ShellConvert(object):
218 def __call__(self,vars,aliases):
219 result=""
220 for v in sorted(vars.keys()):
221 result+=self.toVar(v,vars[v])+"\n"
222 for a in sorted(aliases.keys()):
223 result+=self.toAlias(a,aliases[a])+"\n"
224 return result
226 class BashConvert(ShellConvert):
227 def toVar(self,n,v):
228 if type(v)==list:
229 val=":".join(v)
230 else:
231 val=v
232 if val.find(" "):
233 return 'export %s="%s"' % (n,val)
234 else:
235 return 'export %s=%s' % (n,val)
237 def toAlias(self,n,v):
238 return "alias %s='%s'" % (n,v)
240 class CshConvert(ShellConvert):
241 def __init__(self,sName="csh"):
242 self.shellName=sName
244 def toVar(self,n,v):
245 if type(v)==list:
246 val=":".join(v)
247 else:
248 val=v
249 result='setenv %s "%s"' % (n,val)
250 if n=="PATH":
251 result+="\nset path=(%s)" % " ".join(v)
252 return result
254 def toAlias(self,n,v):
255 val=v.replace(" . ","source ").replace("bash",self.shellName)
256 if val.find("unset ")>=0:
257 val=val.replace("unset ","unsetenv ")
258 # Make sure that more than one export is possible and no wrong = is replaced
259 while val.find("export ")>=0:
260 pos=val.find("export ")
261 val=val.replace("export ","setenv ",1)
262 val=val[:pos]+val[pos:].replace("="," ",1)
264 # Prefix with a variable that tells the script that it is sourced from an alias
265 if val.find("source")>=0:
266 val=("setenv FOAM_SOURCED_FROM_ALIAS %s/tcshrc ; " % here)+val
268 return "alias %s '%s'" % (n,val)
270 class TcshConvert(CshConvert):
271 def __init__(self):
272 CshConvert.__init__(self,"tcsh")
274 class FishConvert(ShellConvert):
275 def toVar(self,n,v):
276 if type(v)==list:
277 val=":".join(v)
278 else:
279 val=v
281 if n=="PATH":
282 result="\nset -x PATH %s" % " ".join(v)
283 else:
284 result='set -x %s "%s"' % (n,val)
286 return result
288 def toAlias(self,n,v):
289 val=v.replace(" . ","source ").replace("bash","fish")
290 if val.find("unset ")>=0:
291 val=val.replace("unset ","set -e ")
292 # Make sure that more than one export is possible and no wrong = is replaced
293 while val.find("export ")>=0:
294 pos=val.find("export ")
295 val=val.replace("export ","set -x ",1)
296 val=val[:pos]+val[pos:].replace("="," ",1)
297 return "alias %s '%s'" % (n,val)
299 class ZshConvert(BashConvert):
300 def toAlias(self,n,v):
301 return BashConvert.toAlias(self,n,v).replace("bash","zsh")
303 shells={"bash" : BashConvert,
304 "zsh" : ZshConvert,
305 "fish" : FishConvert,
306 "csh" : CshConvert,
307 "tcsh" : TcshConvert}
309 try:
310 converter=shells[destShell]()
311 except KeyError:
312 printDebug("No converter for shell",destShell,
313 "Available:"," ".join(shells.keys()))
314 sys.exit(-1)
316 try:
317 result=converter(vars,aliases)
318 except Exception:
319 e = sys.exc_info()[1] # Needed because python 2.5 does not support 'as e'
320 err, detail, tb = sys.exc_info()
321 printDebug("Problem while converting output for",destShell)
322 import traceback
323 traceback.print_exception(err,detail,tb,file=sys.stderr)
324 sys.exit(-1)
326 if PY3:
327 osException=OSError
328 else:
329 osException=IOError
331 try:
332 open(path.abspath(sys.argv[0])+"."+destShell,"w").write(result)
333 except osException:
334 # We are not allowed to write here. Try tmp
335 try:
336 open(path.join("/tmp",
337 path.basename(sys.argv[0])+"."+destShell),"w").write(result)
338 except osException:
339 # Nobody wants this
340 pass
342 # This is the only part that goes to stdout to be sourced by the calling script
343 print_(result)