macOS: Force shell to a supported shell in Terminals opened from Qt Creator

The whole logic (setting up environment, run interactive or non-interactive shell)
is specific to the shell. So force Terminal to use one of the supported ones.
Currently that is zsh and bash.

Fixes: QTCREATORBUG-21712
Change-Id: I83057dd92c5c976f9f5d6f4faf0f596a75d58293
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Eike Ziller
2019-11-08 10:41:20 +01:00
parent 3da2ba530e
commit 817f81cbfd

View File

@@ -27,13 +27,11 @@
import os
import pipes
import stat
import subprocess
import sys
from tempfile import NamedTemporaryFile
def quote_applescript(arg):
return arg.replace('\\', '\\\\').replace('"', '\\"')
def quote_shell(arg):
return pipes.quote(arg)
@@ -42,7 +40,7 @@ def clean_environment_script():
env_to_keep = ' '.join(['_', 'HOME', 'LOGNAME', 'PWD', 'SHELL', 'TMPDIR', 'USER', 'TERM',
'TERM_PROGRAM', 'TERM_PROGRAM_VERSION', 'TERM_SESSION_CLASS_ID',
'TERM_SESSION_ID'])
return '''
return r'''
function ignore() {
local keys="''' + env_to_keep + '''"
local v=$1
@@ -55,10 +53,15 @@ done < <(env)
'''
def system_login_script_bash():
return 'if [ -f /etc/profile ]; then source /etc/profile; fi\n'
return r'''
[ -r /etc/profile ] && source /etc/profile
# fake behavior of /etc/profile as if BASH was set. It isn't for non-interactive shell
export PS1='\h:\W \u\$ '
[ -r /etc/bashrc ] && source /etc/bashrc
'''
def login_script_bash():
return '''
return r'''
if [ -f $HOME/.bash_profile ]; then
source $HOME/.bash_profile
elif [ -f $HOME/.bash_login ]; then
@@ -72,7 +75,7 @@ def system_login_script_zsh():
return '[ -r /etc/profile ] && source /etc/profile\n'
def login_script_zsh():
return '''
return r'''
[ -r $HOME/.zprofile ] && source $HOME/.zprofile
[ -r $HOME/.zshrc ] && source $HOME/.zshrc
[ -r $HOME/.zlogin ] && source $HOME/.zlogin
@@ -82,51 +85,44 @@ def environment_script():
return ''.join(['export ' + quote_shell(key + '=' + os.environ[key]) + '\n'
for key in os.environ])
def apple_script(shell_command):
return '''
--Terminal opens a window by default when it is not running, so check
on applicationIsRunning(applicationName)
tell application "System Events" to count (every process whose name is applicationName)
return result is greater than 0
end applicationIsRunning
set terminalWasRunning to applicationIsRunning("Terminal")
def zsh_setup(shell):
return (shell,
system_login_script_zsh,
login_script_zsh,
shell + ' -c',
shell + ' -d -f')
set cdScript to "{}"
tell application "Terminal"
--do script will open a new window if none given, but terminal already opens one if not running
if terminalWasRunning then
do script cdScript
else
do script cdScript in first window
end if
set currentTab to the result
set currentWindow to first window whose tabs contains currentTab
activate
end tell
'''.format(shell_command)
def bash_setup(shell):
bash = shell if shell is not None and shell.endswith('/bash') else '/bin/bash'
return (bash,
system_login_script_bash,
login_script_bash,
bash + ' -c',
bash + ' --noprofile -l')
def main():
# create temporary file to be sourced into bash that deletes itself
with NamedTemporaryFile(delete=False) as shell_script:
shell = os.environ.get('SHELL')
shell_is_zsh = shell is not None and shell.endswith('/zsh')
system_login_script = system_login_script_zsh if shell_is_zsh else system_login_script_bash
login_script = login_script_zsh if shell_is_zsh else login_script_bash
quoted_shell_script = quote_shell(shell_script.name)
commands = (clean_environment_script() +
system_login_script() + # /etc/profile by default resets the path, so do first
shell, system_login_script, login_script, non_interactive_shell, interactive_shell = (
zsh_setup(shell) if shell is not None and shell.endswith('/zsh')
else bash_setup(shell))
commands = ('#!' + shell + '\n' +
'rm ' + quote_shell(shell_script.name) + '\n' +
clean_environment_script() +
system_login_script() + # /etc/(z)profile by default resets the path, so do first
environment_script() +
login_script() +
'cd ' + quote_shell(os.getcwd()) + '\n' +
' '.join([quote_shell(arg) for arg in sys.argv[1:]]) + '\n' +
'rm ' + quoted_shell_script + '\n' +
('exit\n' if len(sys.argv) > 1 else '')
('exec ' + non_interactive_shell + ' ' +
quote_shell(' '.join([quote_shell(arg) for arg in sys.argv[1:]])) + '\n'
if len(sys.argv) > 1 else 'exec ' + interactive_shell + '\n')
)
shell_script.write(commands)
shell_script.flush()
shell_command = quote_applescript('source ' + quoted_shell_script)
osascript_process = subprocess.Popen(['/usr/bin/osascript'], stdin=subprocess.PIPE)
osascript_process.communicate(apple_script(shell_command))
os.chmod(shell_script.name, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
subprocess.call(['/usr/bin/open', '-a', 'Terminal', shell_script.name])
if __name__ == "__main__":
main()