fix(skills): ibcmd non-interactive — fast-fail вместо зависания на запросе учётки (#28)

ibcmd при отсутствии/неверных учётных данных уходил в интерактивный запрос и
зависал. Эмпирически (реальный ibcmd, macOS+Windows, базы с пользователями):
вис возникает только когда не задан -UserName; stdin=DEVNULL НЕ лечит (наоборот
виснет). Лечит закрытый stdin-пайп (EOF) → ibcmd падает за ~4-7с с внятным
«Идентификация пользователя не выполнена».

- python (12 файлов + stub): run_ibcmd(cmd, has_username) c input="" вместо
  прямого subprocess.run; без таймаута. Остаточный случай python+Windows+нет
  -UserName (ibcmd читает консоль) помечается hint'ом в stderr (English, model-facing).
- PowerShell (12 файлов): Invoke-IbcmdProcess через [System.Diagnostics.Process] +
  RedirectStandardInput + StandardInput.Close() → fast-fail; StandardOutputEncoding
  cp866 (кириллица ibcmd не мойибейлится). Ветка 1cv8/DESIGNER не тронута.
- Жёсткий таймаут не вводим: у вызывающей стороны свой бэкстоп, авто-kill рвал бы
  длинные легитимные операции.
- Синхронный бамп версий ps1+py всех затронутых навыков.

Fixes #28

Co-Authored-By: Korolev Pavel <korolev.vrn@gmail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-30 17:23:59 +03:00
parent 696af58cf7
commit 4b6bdac484
24 changed files with 656 additions and 66 deletions
@@ -1,4 +1,4 @@
# db-load-git v1.9 — Load Git changes into 1C database
# db-load-git v1.10 — Load Git changes into 1C database
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
<#
@@ -167,6 +167,33 @@ if (-not $DryRun) {
# --- Detect engine + validate connection (skip if DryRun) ---
$engine = "1cv8"
if (-not $DryRun) {
function Invoke-IbcmdProcess {
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
param([string]$Exe, [string[]]$IbArgs)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $Exe
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $true
$psi.RedirectStandardInput = $true
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
try {
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
} catch {}
$p = [System.Diagnostics.Process]::Start($psi)
$p.StandardInput.Close()
$out = $p.StandardOutput.ReadToEnd()
$err = $p.StandardError.ReadToEnd()
$p.WaitForExit()
if ($err) { $out += $err }
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
}
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
if ($engine -eq "ibcmd") {
if (-not $InfoBasePath) {
@@ -344,8 +371,9 @@ try {
if ($Password) { $arguments += "--password=$Password" }
$arguments += "--data=$tempDir"
Write-Host "Running: ibcmd $($arguments -join ' ')"
$output = & $V8Path @arguments 2>&1
$exitCode = $LASTEXITCODE
$__ib = Invoke-IbcmdProcess $V8Path $arguments
$output = $__ib.Output
$exitCode = $__ib.ExitCode
if ($exitCode -ne 0) {
Write-Host "Error loading changes (code: $exitCode)" -ForegroundColor Red
if ($output) { Write-Host ($output | Out-String) }
@@ -359,8 +387,9 @@ try {
if ($Password) { $applyArgs += "--password=$Password" }
$applyArgs += "--data=$tempDir"
Write-Host "Running: ibcmd $($applyArgs -join ' ')"
$applyOut = & $V8Path @applyArgs 2>&1
$exitCode = $LASTEXITCODE
$__ib = Invoke-IbcmdProcess $V8Path $applyArgs
$applyOut = $__ib.Output
$exitCode = $__ib.ExitCode
if ($exitCode -eq 0) {
Write-Host "Database configuration updated successfully" -ForegroundColor Green
} else {
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# db-load-git v1.9 — Load Git changes into 1C database
# db-load-git v1.10 — Load Git changes into 1C database
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -78,6 +78,27 @@ def resolve_v8path(v8path):
return v8path
IBCMD_NOUSER_HINT = (
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
"call may block instead of failing. If it does not return promptly, abort and "
"re-run with -UserName and -Password.\n"
)
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
"""Run an ibcmd command non-interactively.
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
On Windows without -UserName ibcmd reads the console directly and may still block —
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
"""
if warn_no_user and os.name == "nt" and not has_username:
sys.stderr.write(IBCMD_NOUSER_HINT)
sys.stderr.flush()
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
def get_object_xml_from_subfile(relative_path):
"""Map sub-file path (BSL, HTML, etc.) to object XML path."""
parts = re.split(r"[\\/]", relative_path)
@@ -287,7 +308,7 @@ def main():
arguments.append(f"--password={args.Password}")
arguments.append(f"--data={ib_data}")
print(f"Running: ibcmd {' '.join(arguments)}")
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
if result.returncode != 0:
print(f"Error loading changes (code: {result.returncode})", file=sys.stderr)
if result.stdout:
@@ -307,7 +328,7 @@ def main():
apply_args.append(f"--password={args.Password}")
apply_args.append(f"--data={ib_data}")
print(f"Running: ibcmd {' '.join(apply_args)}")
ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace")
ar = run_ibcmd([v8path] + apply_args, bool(args.UserName))
exit_code = ar.returncode
if exit_code == 0:
print("Database configuration updated successfully")