Use a new controlling terminal when reading shell environment
This is because some people do things in their rc files based on checking the name of the controlling terminal.
This commit is contained in:
parent
6958ded4c4
commit
bdade7e151
3 changed files with 43 additions and 20 deletions
|
|
@ -118,6 +118,10 @@ def remove_cloexec(fd):
|
|||
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
|
||||
|
||||
|
||||
def remove_blocking(fd):
|
||||
os.set_blocking(fd, False)
|
||||
|
||||
|
||||
def default_env():
|
||||
try:
|
||||
return default_env.env
|
||||
|
|
@ -132,6 +136,13 @@ def set_default_env(val=None):
|
|||
default_env.env = env
|
||||
|
||||
|
||||
def openpty():
|
||||
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
||||
remove_cloexec(slave)
|
||||
fast_data_types.set_iutf8_fd(master, True)
|
||||
return master, slave
|
||||
|
||||
|
||||
class Child:
|
||||
|
||||
child_fd = pid = None
|
||||
|
|
@ -178,9 +189,7 @@ def fork(self):
|
|||
if self.forked:
|
||||
return
|
||||
self.forked = True
|
||||
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
||||
remove_cloexec(slave)
|
||||
fast_data_types.set_iutf8_fd(master, True)
|
||||
master, slave = openpty()
|
||||
stdin, self.stdin = self.stdin, None
|
||||
ready_read_fd, ready_write_fd = os.pipe()
|
||||
remove_cloexec(ready_read_fd)
|
||||
|
|
@ -206,7 +215,7 @@ def fork(self):
|
|||
fast_data_types.thread_write(stdin_write_fd, stdin)
|
||||
os.close(ready_read_fd)
|
||||
self.terminal_ready_fd = ready_write_fd
|
||||
fcntl.fcntl(self.child_fd, fcntl.F_SETFL, fcntl.fcntl(self.child_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
||||
remove_blocking(self.child_fd)
|
||||
return pid
|
||||
|
||||
def mark_terminal_ready(self):
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
from .borders import load_borders_program
|
||||
from .boss import Boss
|
||||
from .child import set_default_env
|
||||
from .child import set_default_env, openpty, remove_blocking
|
||||
from .cli import create_opts, parse_args
|
||||
from .config import cached_values_for, initial_window_size_func
|
||||
from .constants import (
|
||||
|
|
@ -203,23 +203,37 @@ def macos_cmdline(argv_args):
|
|||
return ans
|
||||
|
||||
|
||||
def read_shell_environment(opts):
|
||||
def read_shell_environment(opts=None):
|
||||
if not hasattr(read_shell_environment, 'ans'):
|
||||
import subprocess
|
||||
from .session import resolved_shell
|
||||
shell = resolved_shell(opts)
|
||||
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=subprocess.PIPE)
|
||||
raw = p.stdout.read()
|
||||
if p.wait() == 0:
|
||||
raw = raw.decode('utf-8', 'replace')
|
||||
ans = read_shell_environment.ans = {}
|
||||
for line in raw.splitlines():
|
||||
k, v = line.partition('=')[::2]
|
||||
if k and v:
|
||||
ans[k] = v
|
||||
else:
|
||||
log_error('Failed to run shell to read its environment')
|
||||
read_shell_environment.ans = {}
|
||||
master, slave = openpty()
|
||||
remove_blocking(master)
|
||||
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=slave, stdin=slave, stderr=slave, start_new_session=True, close_fds=True)
|
||||
with os.fdopen(master, 'rb') as stdout, os.fdopen(slave, 'wb'):
|
||||
raw = b''
|
||||
while p.wait(0.01) is None:
|
||||
with suppress(Exception):
|
||||
raw += stdout.read()
|
||||
if p.returncode == 0:
|
||||
while True:
|
||||
try:
|
||||
x = stdout.read()
|
||||
except Exception:
|
||||
break
|
||||
if not x:
|
||||
break
|
||||
raw += x
|
||||
raw = raw.decode('utf-8', 'replace')
|
||||
ans = read_shell_environment.ans = {}
|
||||
for line in raw.splitlines():
|
||||
k, v = line.partition('=')[::2]
|
||||
if k and v:
|
||||
ans[k] = v
|
||||
else:
|
||||
log_error('Failed to run shell to read its environment')
|
||||
read_shell_environment.ans = {}
|
||||
return read_shell_environment.ans
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ def set_cwd(self, val):
|
|||
self.tabs[-1].cwd = val
|
||||
|
||||
|
||||
def resolved_shell(opts):
|
||||
ans = opts.shell
|
||||
def resolved_shell(opts=None):
|
||||
ans = getattr(opts, 'shell', '.')
|
||||
if ans == '.':
|
||||
ans = [shell_path]
|
||||
else:
|
||||
|
|
|
|||
Loading…
Reference in a new issue