TUI-пульт на Textual вместо текстового меню

Списки баз стенда и локальных дампов на одном экране, фильтр сужает их
на каждом набранном символе. Enter по базе открывает окно параметров
дампа с галочкой автоподнятия: снята — только dump, поднята — dump плюс
restore. Правки полей уезжают в копию конфига, config.json не трогается.

Ядро получило четыре хука для UI (лог, границы шагов, пароль, отмена),
run() читает вывод утилит построчно через Popen, поэтому журнал
наполняется во время работы pg_dump. Текстовый режим, CLI и --dry-run
ведут себя как раньше; без textual или вне tty пульт не запускается.

Журнал разворачивается на весь экран по F4 и сам на старте операции.
Раскладка адаптивная: narrow ниже 100 колонок, short ниже 32 строк.
Ctrl-хоткеи продублированы кириллицей — русская раскладка их не глушит.

Запуск через run.ps1 (venv, UTF-8-консоль, -Setup и -Tests).
Проверка — tests_tui.py: 46 тестов, TUI гоняется headless через Pilot.
This commit is contained in:
2026-08-20 05:21:52 +03:00
parent b30406bbf6
commit 9fdb02c72a
10 changed files with 3211 additions and 30 deletions
+69
View File
@@ -0,0 +1,69 @@
<#
.SYNOPSIS
Запуск pg-stand-sync: находит интерпретатор, чинит кодировку консоли, пробрасывает аргументы.
.EXAMPLE
.\run.ps1 # пульт (TUI)
.\run.ps1 list # базы на стенде
.\run.ps1 --dry-run sync zpas # проверка команд без выполнения
.\run.ps1 -Setup # создать .venv и поставить зависимости
.\run.ps1 -Tests # прогнать тесты
#>
[CmdletBinding()]
param(
# Создать .venv и установить requirements.txt
[switch]$Setup,
# Прогнать tests_tui.py вместо запуска приложения
[switch]$Tests,
# Всё остальное уходит в pg_stand_sync.py как есть
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Rest
)
$ErrorActionPreference = 'Stop'
$root = $PSScriptRoot
$venvPython = Join-Path $root '.venv\Scripts\python.exe'
# Русский лог и рамки Textual в cp866-консоли превращаются в мусор
[Console]::OutputEncoding = [Text.Encoding]::UTF8
[Console]::InputEncoding = [Text.Encoding]::UTF8
$env:PYTHONIOENCODING = 'utf-8'
function Find-Python {
if (Test-Path $venvPython) { return $venvPython }
foreach ($name in 'python', 'py') {
$cmd = Get-Command $name -ErrorAction SilentlyContinue
if ($cmd) { return $cmd.Source }
}
throw 'Python не найден: поставьте его или создайте окружение через .\run.ps1 -Setup'
}
if ($Setup) {
if (-not (Test-Path $venvPython)) {
$bootstrap = Find-Python
Write-Host "создаю .venv ($bootstrap)" -ForegroundColor Cyan
& $bootstrap -m venv (Join-Path $root '.venv')
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}
Write-Host 'ставлю зависимости' -ForegroundColor Cyan
& $venvPython -m pip install --disable-pip-version-check -r (Join-Path $root 'requirements.txt')
exit $LASTEXITCODE
}
$python = Find-Python
if ($Tests) {
& $python -m pytest (Join-Path $root 'tests_tui.py') -q @Rest
exit $LASTEXITCODE
}
# Без textual приложение молча откатится в текстовое меню — предупредить, пока не поздно
& $python -c 'import textual' 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Host 'textual не установлен — откроется текстовый режим. Полный пульт: .\run.ps1 -Setup' `
-ForegroundColor Yellow
}
& $python (Join-Path $root 'pg_stand_sync.py') @Rest
exit $LASTEXITCODE