The subprocess stdout was a pipe to the TUI. When the TUI exited, the pipe broke (SIGPIPE) and killed the backup process. Now the subprocess writes to a log file in WORK_DIR, and the TUI tails it for live display. When the TUI exits, the subprocess keeps running because it writes to a file, not a pipe. On restart, the log file is loaded to show output for reconnected or finished background jobs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
import asyncio
|
|
import os
|
|
from pathlib import Path
|
|
|
|
|
|
def _gniza_bin() -> str:
|
|
gniza_dir = os.environ.get("GNIZA_DIR", "")
|
|
if gniza_dir:
|
|
return str(Path(gniza_dir) / "bin" / "gniza")
|
|
here = Path(__file__).resolve().parent.parent / "bin" / "gniza"
|
|
if here.is_file():
|
|
return str(here)
|
|
return "gniza"
|
|
|
|
|
|
async def run_cli(*args: str) -> tuple[int, str, str]:
|
|
cmd = [_gniza_bin(), "--cli"] + list(args)
|
|
proc = await asyncio.create_subprocess_exec(
|
|
*cmd,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE,
|
|
)
|
|
stdout, stderr = await proc.communicate()
|
|
return proc.returncode or 0, stdout.decode(), stderr.decode()
|
|
|
|
|
|
async def start_cli_process(*args: str, log_file: str | None = None) -> asyncio.subprocess.Process:
|
|
cmd = [_gniza_bin(), "--cli"] + list(args)
|
|
if log_file:
|
|
fh = open(log_file, "w")
|
|
proc = await asyncio.create_subprocess_exec(
|
|
*cmd,
|
|
stdout=fh,
|
|
stderr=asyncio.subprocess.STDOUT,
|
|
start_new_session=True,
|
|
)
|
|
fh.close()
|
|
return proc
|
|
return await asyncio.create_subprocess_exec(
|
|
*cmd,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.STDOUT,
|
|
start_new_session=True,
|
|
)
|
|
|
|
|
|
async def stream_cli(callback, *args: str) -> int:
|
|
cmd = [_gniza_bin(), "--cli"] + list(args)
|
|
proc = await asyncio.create_subprocess_exec(
|
|
*cmd,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.STDOUT,
|
|
)
|
|
while True:
|
|
line = await proc.stdout.readline()
|
|
if not line:
|
|
break
|
|
callback(line.decode().rstrip("\n"))
|
|
await proc.wait()
|
|
return proc.returncode or 0
|