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
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
18 print_
= getattr(builtins
, "print")
21 def print_(*args
, **kwargs
):
22 """The new-style print function."""
23 fp
= kwargs
.pop("file", sys
.stdout
)
27 if not isinstance(data
, basestring
):
31 sep
= kwargs
.pop("sep", None)
33 if isinstance(sep
, unicode):
35 elif not isinstance(sep
, str):
36 raise TypeError("sep must be None or a string")
37 end
= kwargs
.pop("end", None)
39 if isinstance(end
, unicode):
41 elif not isinstance(end
, str):
42 raise TypeError("end must be None or a string")
44 raise TypeError("invalid keyword arguments to print()")
47 if isinstance(arg
, unicode):
51 newline
= unicode("\n")
60 for i
, arg
in enumerate(args
):
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
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]))
83 printDebug("Using scripts in",here
)
88 # Variables like WM_COMPILER=Gcc46
89 additional
=sys
.argv
[2:]
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",
98 "WM_PROJECT_USER_DIR",
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
+"'"
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
122 p
= Popen(cmd
, shell
=True,
123 stdin
=PIPE
, stdout
=PIPE
, stderr
=STDOUT
, close_fds
=True)
124 (rein
,raus
)=(p
.stdin
,p
.stdout
)
127 lines
=[l
.strip().decode() for l
in raus
.readlines()]
131 if verbose
or ret
!=0:
132 printDebug("========= Script output start")
135 printDebug("========= Script output end")
138 printDebug("Command return code",ret
,". There seems to be a problem")
140 def extractVariables(lines
):
142 # different forms if bash is called as sh
143 prefixes
=["export ","declare -x "]
151 name
=l
[len(pref
):pos
]
154 if val
[0]=='"' and val
[-1]=='"':
162 def extractAliases(lines
):
165 pref
="" # if called as sh
166 if l
.find("alias ")==0:
169 aliases
[l
[len(pref
):pos
]]=l
[pos
+2:-1]
173 def changedVars(old
,new
):
182 def splitPaths(orig
):
184 for k
in orig
.keys():
185 if k
.find("PATH")>=0 and orig
[k
].find(":")>=0:
186 new
[k
]=orig
[k
].split(":")
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")]
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")
209 traceback
.print_exception(err
,detail
,tb
,file=sys
.stderr
)
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
):
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"
226 class BashConvert(ShellConvert
):
233 return 'export %s="%s"' % (n
,val
)
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"):
249 result
='setenv %s "%s"' % (n
,val
)
251 result
+="\nset path=(%s)" % " ".join(v
)
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
):
272 CshConvert
.__init
__(self
,"tcsh")
274 class FishConvert(ShellConvert
):
282 result
="\nset -x PATH %s" % " ".join(v
)
284 result
='set -x %s "%s"' % (n
,val
)
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
,
305 "fish" : FishConvert
,
307 "tcsh" : TcshConvert
}
310 converter
=shells
[destShell
]()
312 printDebug("No converter for shell",destShell
,
313 "Available:"," ".join(shells
.keys()))
317 result
=converter(vars,aliases
)
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
)
323 traceback
.print_exception(err
,detail
,tb
,file=sys
.stderr
)
332 open(path
.abspath(sys
.argv
[0])+"."+destShell
,"w").write(result
)
334 # We are not allowed to write here. Try tmp
336 open(path
.join("/tmp",
337 path
.basename(sys
.argv
[0])+"."+destShell
),"w").write(result
)
342 # This is the only part that goes to stdout to be sourced by the calling script