feat(db-dump-dt,db-load-dt): пилот ibcmd (движок по имени exe в -V8Path)

Если -V8Path указывает на ibcmd.exe — операция выполняется через утилиту
автономного сервера (offline, без запуска платформы), иначе как прежде
через 1cv8 DESIGNER. Выбор движка неявный (sniff имени exe), без новых
параметров; в реестре .v8-project.json пользователь прописывает v8path
= путь к ibcmd.exe.

Пилот на dt-паре:
- dump:    ibcmd infobase dump --db-path=<base> [--user][--password] <dt>
- restore: ibcmd infobase restore --db-path=<base> [--create-database
  если нет 1Cv8.1CD] [--user][--password] <dt>
Только файловые базы (серверные под ibcmd → понятная ошибка: нужны креды
СУБД, которых нет в реестре). Вывод ibcmd (UTF-8) захватывается из
stdout/stderr (нет /Out-файла). 1cv8-ветка без изменений. Версия 1.1→1.2.

E2E: dump 115281б, restore round-trip (свежий каталог +--create-database,
overwrite существующей без флага), 1cv8-регресс, server+ibcmd→ошибка.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-21 15:18:41 +03:00
parent 3d36c20269
commit 11bab7669d
6 changed files with 123 additions and 10 deletions
+3 -1
View File
@@ -45,7 +45,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <п
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
@@ -54,6 +54,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <п
| `-OutputFile <путь>` | да | Путь к выходному DT-файлу |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
>
> Если `-V8Path` указывает на `ibcmd.exe` — выгрузка идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`).
## Примеры
@@ -1,4 +1,4 @@
# db-dump-dt v1.1 — Dump 1C information base to DT file
# db-dump-dt v1.2 — Dump 1C information base to DT file
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
<#
.SYNOPSIS
@@ -102,8 +102,16 @@ if (-not (Test-Path $V8Path)) {
exit 1
}
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
# --- Validate connection ---
if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) {
if ($engine -eq "ibcmd") {
if (-not $InfoBasePath) {
Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red
exit 1
}
} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) {
Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red
exit 1
}
@@ -119,6 +127,26 @@ $tempDir = Join-Path $env:TEMP "db_dump_dt_$(Get-Random)"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
try {
if ($engine -eq "ibcmd") {
# --- ibcmd branch (file infobase only) ---
$arguments = @("infobase", "dump", "--db-path=$InfoBasePath")
if ($UserName) { $arguments += "--user=$UserName" }
if ($Password) { $arguments += "--password=$Password" }
$arguments += "$OutputFile"
Write-Host "Running: ibcmd $($arguments -join ' ')"
$output = & $V8Path @arguments 2>&1
$exitCode = $LASTEXITCODE
if ($exitCode -eq 0) {
Write-Host "Information base dumped successfully to: $OutputFile" -ForegroundColor Green
} else {
Write-Host "Error dumping information base (code: $exitCode)" -ForegroundColor Red
}
if ($output) { Write-Host ($output | Out-String) }
exit $exitCode
}
# --- 1cv8 branch ---
# --- Build arguments ---
$arguments = @("DESIGNER")
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# db-dump-dt v1.1 — Dump 1C information base to DT file
# db-dump-dt v1.2 — Dump 1C information base to DT file
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -82,9 +82,14 @@ def main():
args = parser.parse_args()
v8path = resolve_v8path(args.V8Path)
engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8"
# --- Validate connection ---
if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef):
if engine == "ibcmd":
if not args.InfoBasePath:
print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr)
sys.exit(1)
elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef):
print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr)
sys.exit(1)
@@ -93,6 +98,26 @@ def main():
if out_dir and not os.path.isdir(out_dir):
os.makedirs(out_dir, exist_ok=True)
# --- ibcmd branch (file infobase only) ---
if engine == "ibcmd":
arguments = ["infobase", "dump", f"--db-path={args.InfoBasePath}"]
if args.UserName:
arguments.append(f"--user={args.UserName}")
if args.Password:
arguments.append(f"--password={args.Password}")
arguments.append(args.OutputFile)
print(f"Running: ibcmd {' '.join(arguments)}")
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
if result.returncode == 0:
print(f"Information base dumped successfully to: {args.OutputFile}")
else:
print(f"Error dumping information base (code: {result.returncode})", file=sys.stderr)
if result.stdout:
print(result.stdout)
if result.stderr:
print(result.stderr, file=sys.stderr)
sys.exit(result.returncode)
# --- Temp dir ---
temp_dir = os.path.join(tempfile.gettempdir(), f"db_dump_dt_{random.randint(0, 999999)}")
os.makedirs(temp_dir, exist_ok=True)
+3 -1
View File
@@ -59,7 +59,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" <п
| Параметр | Обязательный | Описание |
|----------|:------------:|----------|
| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) |
| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` |
| `-InfoBasePath <путь>` | * | Файловая база |
| `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) |
| `-InfoBaseRef <имя>` | * | Имя базы на сервере |
@@ -70,6 +70,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" <п
| `-UnlockCode <код>` | нет | Код разблокировки (`/UC`), если заблокировано начало сеансов |
> `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef`
>
> Если `-V8Path` указывает на `ibcmd.exe` — загрузка идёт через автономный сервер (быстрее, без запуска платформы); поддерживаются **только файловые базы** (`-InfoBasePath`). Базу создаст при отсутствии.
## После выполнения
@@ -1,4 +1,4 @@
# db-load-dt v1.1 — Load 1C information base from DT file
# db-load-dt v1.2 — Load 1C information base from DT file
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
<#
.SYNOPSIS
@@ -115,8 +115,16 @@ if (-not (Test-Path $V8Path)) {
exit 1
}
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
# --- Validate connection ---
if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) {
if ($engine -eq "ibcmd") {
if (-not $InfoBasePath) {
Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath)" -ForegroundColor Red
exit 1
}
} elseif (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) {
Write-Host "Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef" -ForegroundColor Red
exit 1
}
@@ -132,6 +140,27 @@ $tempDir = Join-Path $env:TEMP "db_load_dt_$(Get-Random)"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
try {
if ($engine -eq "ibcmd") {
# --- ibcmd branch (file infobase only) ---
$arguments = @("infobase", "restore", "--db-path=$InfoBasePath")
if (-not (Test-Path (Join-Path $InfoBasePath "1Cv8.1CD"))) { $arguments += "--create-database" }
if ($UserName) { $arguments += "--user=$UserName" }
if ($Password) { $arguments += "--password=$Password" }
$arguments += "$InputFile"
Write-Host "Running: ibcmd $($arguments -join ' ')"
$output = & $V8Path @arguments 2>&1
$exitCode = $LASTEXITCODE
if ($exitCode -eq 0) {
Write-Host "Information base restored successfully from: $InputFile" -ForegroundColor Green
} else {
Write-Host "Error restoring information base (code: $exitCode)" -ForegroundColor Red
}
if ($output) { Write-Host ($output | Out-String) }
exit $exitCode
}
# --- 1cv8 branch ---
# --- Build arguments ---
$arguments = @("DESIGNER")
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# db-load-dt v1.1 — Load 1C information base from DT file
# db-load-dt v1.2 — Load 1C information base from DT file
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -84,9 +84,14 @@ def main():
args = parser.parse_args()
v8path = resolve_v8path(args.V8Path)
engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8"
# --- Validate connection ---
if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef):
if engine == "ibcmd":
if not args.InfoBasePath:
print("Error: ibcmd supports file infobases only (use -InfoBasePath)", file=sys.stderr)
sys.exit(1)
elif not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef):
print("Error: specify -InfoBasePath or -InfoBaseServer + -InfoBaseRef", file=sys.stderr)
sys.exit(1)
@@ -95,6 +100,28 @@ def main():
print(f"Error: input file not found: {args.InputFile}", file=sys.stderr)
sys.exit(1)
# --- ibcmd branch (file infobase only) ---
if engine == "ibcmd":
arguments = ["infobase", "restore", f"--db-path={args.InfoBasePath}"]
if not os.path.isfile(os.path.join(args.InfoBasePath, "1Cv8.1CD")):
arguments.append("--create-database")
if args.UserName:
arguments.append(f"--user={args.UserName}")
if args.Password:
arguments.append(f"--password={args.Password}")
arguments.append(args.InputFile)
print(f"Running: ibcmd {' '.join(arguments)}")
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
if result.returncode == 0:
print(f"Information base restored successfully from: {args.InputFile}")
else:
print(f"Error restoring information base (code: {result.returncode})", file=sys.stderr)
if result.stdout:
print(result.stdout)
if result.stderr:
print(result.stderr, file=sys.stderr)
sys.exit(result.returncode)
# --- Temp dir ---
temp_dir = os.path.join(tempfile.gettempdir(), f"db_load_dt_{random.randint(0, 999999)}")
os.makedirs(temp_dir, exist_ok=True)