This is an automated email from the ASF dual-hosted git repository.
ash pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 9d6bebe9690 Fix terminal size and signal handling for `airflow db
shell` (#49004)
9d6bebe9690 is described below
commit 9d6bebe9690a3f21a00044c0aeceaded86484a0c
Author: Ash Berlin-Taylor <[email protected]>
AuthorDate: Wed Apr 9 12:23:33 2025 +0100
Fix terminal size and signal handling for `airflow db shell` (#49004)
This passes along `^C` to the subprocess, which enables things like
cancelling
the current SQL statement in `psql`.
This also correctly sets the terminal size for the pty, and updates the size
on WINCH. This isn't 100% perfect (there's a few edge cases with the pager,
and the inline editor sometimes doesn't fully update) but it's miles better
than it was.
Closes #26186
---
airflow-core/src/airflow/utils/process_utils.py | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/airflow-core/src/airflow/utils/process_utils.py
b/airflow-core/src/airflow/utils/process_utils.py
index 99d0034975b..f46b90bcbf8 100644
--- a/airflow-core/src/airflow/utils/process_utils.py
+++ b/airflow-core/src/airflow/utils/process_utils.py
@@ -19,6 +19,7 @@
from __future__ import annotations
+import array
import errno
import logging
import os
@@ -31,6 +32,7 @@ import sys
from airflow.utils.platform import IS_WINDOWS
if not IS_WINDOWS:
+ import fcntl
import pty
import termios
import tty
@@ -210,10 +212,12 @@ def execute_interactive(cmd: list[str], **kwargs) -> None:
old_tty = termios.tcgetattr(sys.stdin)
old_sigint_handler = signal.getsignal(signal.SIGINT)
+ old_winch_handler = signal.getsignal(signal.SIGWINCH)
tty.setcbreak(sys.stdin.fileno())
# open pseudo-terminal to interact with subprocess
primary_fd, secondary_fd = pty.openpty()
+
try:
with subprocess.Popen(
cmd,
@@ -224,7 +228,21 @@ def execute_interactive(cmd: list[str], **kwargs) -> None:
**kwargs,
) as proc:
# ignore SIGINT in the parent process
- signal.signal(signal.SIGINT, signal.SIG_IGN)
+ def _sighandler(sig, frame):
+ proc.send_signal(sig)
+
+ def _sigwinch(sig, frame):
+ # On Py3.11+ we could use termios.tcgetwinsize/tcsetwinsize
instead
+ buf = array.array("h", [0, 0, 0, 0])
+
+ fcntl.ioctl(pty.STDOUT_FILENO, termios.TIOCGWINSZ, buf, True)
+ fcntl.ioctl(secondary_fd, termios.TIOCSWINSZ, buf)
+
+ # Set the initial size too
+ _sigwinch(signal.SIGWINCH, None)
+
+ signal.signal(signal.SIGINT, _sighandler)
+ signal.signal(signal.SIGWINCH, _sigwinch)
while proc.poll() is None:
readable_fbs, _, _ = select.select([sys.stdin, primary_fd],
[], [], 0)
if sys.stdin in readable_fbs:
@@ -233,10 +251,11 @@ def execute_interactive(cmd: list[str], **kwargs) -> None:
if primary_fd in readable_fbs:
output_data = os.read(primary_fd, 10240)
if output_data:
- os.write(sys.stdout.fileno(), output_data)
+ os.write(pty.STDOUT_FILENO, output_data)
finally:
# restore tty settings back
signal.signal(signal.SIGINT, old_sigint_handler)
+ signal.signal(signal.SIGWINCH, old_winch_handler)
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)