Use pty for capturing and echoing cmd output

This commit is contained in:
Kivi Kaitaniemi
2025-05-01 17:10:16 +03:00
parent ec19b21244
commit bce9be5ebc
+9 -45
View File
@@ -4,6 +4,7 @@ Library module for decman.
import json import json
import os import os
import pty
import shutil import shutil
import subprocess import subprocess
import sys import sys
@@ -907,55 +908,18 @@ def echo_and_capture_command(program: list[str]) -> tuple[int, str]:
Returns a tuple containing the return code of the program as well as all output of the program. Returns a tuple containing the return code of the program as well as all output of the program.
""" """
with subprocess.Popen(
program, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
) as process:
os.set_blocking(process.stdout.fileno(), False)
output_thread = _OutputCapturingThread(process.stdout) output = ""
output_thread.start()
os.set_blocking(sys.stdin.fileno(), False) def read(fd):
nonlocal output
buffer = os.read(fd, 1024)
output += buffer.decode(encoding="utf-8")
return buffer
# Capture stdin and forward it to the process in a non-blocking manner returncode = os.waitstatus_to_exitcode(pty.spawn(program, read))
while process.poll() is None:
inp = sys.stdin.readline()
if inp: return (returncode, output)
process.stdin.write(inp.encode())
process.stdin.flush()
time.sleep(0.1)
os.set_blocking(sys.stdin.fileno(), True)
output_thread.done = True
output_thread.join()
# Capture any output that may not have been yet captured
output = output_thread.output
missing_output = process.stdout.read()
if missing_output:
output += missing_output.decode()
return (process.returncode, output)
class _OutputCapturingThread(threading.Thread):
def __init__(self, stream):
super().__init__()
self._stream = stream
self.output = ""
self.done = False
def run(self):
while not self.done and not self._stream.closed:
output = self._stream.read(1000)
if output:
output = output.decode()
self.output += output
print(output, end="", flush=True)
time.sleep(0.1)
class Systemd: class Systemd: