From 27b9d539e01f8bf295497d402af994da401bc2ce Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 21 Jun 2026 16:33:07 +0300 Subject: [PATCH] =?UTF-8?q?feat(db):=20ibcmd=20=D0=B4=D0=BB=D1=8F=20=D1=87?= =?UTF-8?q?=D0=B0=D1=81=D1=82=D0=B8=D1=87=D0=BD=D0=BE=D0=B9=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8/=D0=B7=D0=B0=D0=B3=D1=80?= =?UTF-8?q?=D1=83=D0=B7=D0=BA=D0=B8=20=D0=B8=D0=B7=20=D0=B8=D1=81=D1=85?= =?UTF-8?q?=D0=BE=D0=B4=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Закрыты частичные режимы, ранее дававшие «use 1cv8»: - db-dump-xml Mode=Partial → ibcmd config export objects <имена> --out= (выгрузка указанных объектов конфигурации); - db-load-xml Mode=Partial / -Files / -ListFile → ibcmd config import files <отн.пути> --base-dir= (--base-dir обязателен); - db-load-git → добавлена ibcmd-поддержка (раньше отсутствовала): config import files <изменённые из git> --base-dir=, с цепочкой config apply --force при -UpdateDB; DryRun не трогает движок. Несовместимое под ibcmd по-прежнему даёт чистую ошибку: -Format Plain, -AllExtensions, db-dump-xml Mode UpdateInfo. 1cv8-ветки без изменений. Версии: db-dump-xml 1.2→1.3, db-load-xml 1.6→1.7, db-load-git 1.5→1.6. E2E: export objects (только указанные объекты), import files round-trip (+apply), db-load-git staged→import files+apply, DryRun, error-кейсы, 1cv8-регресс Partial — всё зелёное. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../db-dump-xml/scripts/db-dump-xml.ps1 | 19 ++++--- .../skills/db-dump-xml/scripts/db-dump-xml.py | 21 +++++--- .claude/skills/db-load-git/SKILL.md | 4 +- .../db-load-git/scripts/db-load-git.ps1 | 52 +++++++++++++++++-- .../skills/db-load-git/scripts/db-load-git.py | 52 +++++++++++++++++-- .../db-load-xml/scripts/db-load-xml.ps1 | 29 ++++++++--- .../skills/db-load-xml/scripts/db-load-xml.py | 31 ++++++++--- 7 files changed, 175 insertions(+), 33 deletions(-) diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 index c6702713..e47aa7b8 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.ps1 @@ -1,4 +1,4 @@ -# db-dump-xml v1.2 — Dump 1C configuration to XML files +# db-dump-xml v1.3 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -182,13 +182,20 @@ try { Write-Host "Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red exit 1 } - if ($Mode -eq "Partial" -or $Mode -eq "UpdateInfo") { - Write-Host "Error: ibcmd config export supports Mode Full/Changes only; use 1cv8 for $Mode" -ForegroundColor Red + if ($Mode -eq "UpdateInfo") { + Write-Host "Error: ibcmd config export does not support Mode UpdateInfo; use 1cv8" -ForegroundColor Red exit 1 } - $arguments = @("infobase", "config", "export", "--db-path=$InfoBasePath") - if ($Extension) { $arguments += "--extension=$Extension" } - $arguments += "$ConfigDir" + if ($Mode -eq "Partial") { + $objList = @($Objects -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) + $arguments = @("infobase", "config", "export", "objects") + $objList + $arguments += "--out=$ConfigDir", "--db-path=$InfoBasePath" + if ($Extension) { $arguments += "--extension=$Extension" } + } else { + $arguments = @("infobase", "config", "export", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$ConfigDir" + } Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py index cbb21d8d..3436dea0 100644 --- a/.claude/skills/db-dump-xml/scripts/db-dump-xml.py +++ b/.claude/skills/db-dump-xml/scripts/db-dump-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-dump-xml v1.2 — Dump 1C configuration to XML files +# db-dump-xml v1.3 — Dump 1C configuration to XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -127,13 +127,20 @@ def main(): if args.AllExtensions: print("Error: ibcmd config export does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) sys.exit(1) - if args.Mode in ("Partial", "UpdateInfo"): - print(f"Error: ibcmd config export supports Mode Full/Changes only; use 1cv8 for {args.Mode}", file=sys.stderr) + if args.Mode == "UpdateInfo": + print("Error: ibcmd config export does not support Mode UpdateInfo; use 1cv8", file=sys.stderr) sys.exit(1) - arguments = ["infobase", "config", "export", f"--db-path={args.InfoBasePath}"] - if args.Extension: - arguments.append(f"--extension={args.Extension}") - arguments.append(args.ConfigDir) + if args.Mode == "Partial": + obj_list = [o.strip() for o in args.Objects.split(",") if o.strip()] + arguments = ["infobase", "config", "export", "objects"] + obj_list + arguments += [f"--out={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + else: + arguments = ["infobase", "config", "export", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.ConfigDir) print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode == 0: diff --git a/.claude/skills/db-load-git/SKILL.md b/.claude/skills/db-load-git/SKILL.md index d260aba0..11a544c9 100644 --- a/.claude/skills/db-load-git/SKILL.md +++ b/.claude/skills/db-load-git/SKILL.md @@ -45,7 +45,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" < | Параметр | Обязательный | Описание | |----------|:------------:|----------| -| `-V8Path <путь>` | нет | Каталог bin платформы (или полный путь к 1cv8.exe) | +| `-V8Path <путь>` | нет | Каталог bin платформы, или полный путь к `1cv8.exe` / `ibcmd.exe` | | `-InfoBasePath <путь>` | * | Файловая база | | `-InfoBaseServer <сервер>` | * | Сервер 1С (для серверной базы) | | `-InfoBaseRef <имя>` | * | Имя базы на сервере | @@ -61,6 +61,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" < | `-UpdateDB` | нет | После загрузки сразу обновить конфигурацию БД (`/UpdateDBCfg`) | > `*` — нужен либо `-InfoBasePath`, либо пара `-InfoBaseServer` + `-InfoBaseRef` +> +> Если `-V8Path` указывает на `ibcmd.exe` — загрузка идёт через автономный сервер (`config import files`); поддерживаются **только файловые базы** (`-InfoBasePath`). ## После выполнения diff --git a/.claude/skills/db-load-git/scripts/db-load-git.ps1 b/.claude/skills/db-load-git/scripts/db-load-git.ps1 index 96767f23..5650c1d1 100644 --- a/.claude/skills/db-load-git/scripts/db-load-git.ps1 +++ b/.claude/skills/db-load-git/scripts/db-load-git.ps1 @@ -1,4 +1,4 @@ -# db-load-git v1.5 — Load Git changes into 1C database +# db-load-git v1.6 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -163,9 +163,16 @@ if (-not $DryRun) { } } -# --- Validate connection (skip if DryRun) --- +# --- Detect engine + validate connection (skip if DryRun) --- +$engine = "1cv8" if (-not $DryRun) { - if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) { + $engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" } + 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 } @@ -319,6 +326,45 @@ $tempDir = Join-Path $env:TEMP "db_load_git_$(Get-Random)" New-Item -ItemType Directory -Path $tempDir -Force | Out-Null try { + if ($engine -eq "ibcmd") { + # --- ibcmd branch (file infobase only; import specific files) --- + if ($Format -eq "Plain") { + Write-Host "Error: ibcmd config import supports hierarchical format only (use -Format Hierarchical or 1cv8)" -ForegroundColor Red + exit 1 + } + if ($AllExtensions) { + Write-Host "Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "import", "files") + $configFiles + $arguments += "--base-dir=$ConfigDir", "--db-path=$InfoBasePath" + if ($Extension) { $arguments += "--extension=$Extension" } + Write-Host "Running: ibcmd $($arguments -join ' ')" + $output = & $V8Path @arguments 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { + Write-Host "Error loading changes (code: $exitCode)" -ForegroundColor Red + if ($output) { Write-Host ($output | Out-String) } + exit $exitCode + } + Write-Host "Changes loaded successfully ($($configFiles.Count) files)" -ForegroundColor Green + if ($output) { Write-Host ($output | Out-String) } + if ($UpdateDB) { + $applyArgs = @("infobase", "config", "apply", "--db-path=$InfoBasePath", "--force") + Write-Host "Running: ibcmd $($applyArgs -join ' ')" + $applyOut = & $V8Path @applyArgs 2>&1 + $exitCode = $LASTEXITCODE + if ($exitCode -eq 0) { + Write-Host "Database configuration updated successfully" -ForegroundColor Green + } else { + Write-Host "Error updating database configuration (code: $exitCode)" -ForegroundColor Red + } + if ($applyOut) { Write-Host ($applyOut | Out-String) } + } + exit $exitCode + } + + # --- 1cv8 branch --- # --- Write list file (UTF-8 with BOM) --- $listFile = Join-Path $tempDir "load_list.txt" $utf8Bom = New-Object System.Text.UTF8Encoding($true) diff --git a/.claude/skills/db-load-git/scripts/db-load-git.py b/.claude/skills/db-load-git/scripts/db-load-git.py index c51444e9..dcf22dfb 100644 --- a/.claude/skills/db-load-git/scripts/db-load-git.py +++ b/.claude/skills/db-load-git/scripts/db-load-git.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-git v1.5 — Load Git changes into 1C database +# db-load-git v1.6 — Load Git changes into 1C database # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -125,9 +125,15 @@ def main(): if not args.DryRun: v8path = resolve_v8path(args.V8Path) - # --- Validate connection (skip if DryRun) --- + # --- Detect engine + validate connection (skip if DryRun) --- + engine = "1cv8" if not args.DryRun: - if not args.InfoBasePath and (not args.InfoBaseServer or not args.InfoBaseRef): + engine = "ibcmd" if os.path.basename(v8path).lower().startswith("ibcmd") else "1cv8" + 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) @@ -248,6 +254,46 @@ def main(): os.makedirs(temp_dir, exist_ok=True) try: + if engine == "ibcmd": + # --- ibcmd branch (file infobase only; import specific files) --- + if args.Format == "Plain": + print("Error: ibcmd config import supports hierarchical format only (use -Format Hierarchical or 1cv8)", file=sys.stderr) + sys.exit(1) + if args.AllExtensions: + print("Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "import", "files"] + config_files + arguments += [f"--base-dir={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + 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"Error loading changes (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) + print(f"Changes loaded successfully ({len(config_files)} files)") + if result.stdout: + print(result.stdout) + exit_code = 0 + if args.UpdateDB: + apply_args = ["infobase", "config", "apply", f"--db-path={args.InfoBasePath}", "--force"] + print(f"Running: ibcmd {' '.join(apply_args)}") + ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace") + exit_code = ar.returncode + if exit_code == 0: + print("Database configuration updated successfully") + else: + print(f"Error updating database configuration (code: {exit_code})", file=sys.stderr) + if ar.stdout: + print(ar.stdout) + if ar.stderr: + print(ar.stderr, file=sys.stderr) + sys.exit(exit_code) + # --- Write list file (UTF-8 with BOM) --- list_file = os.path.join(temp_dir, "load_list.txt") with open(list_file, "w", encoding="utf-8-sig") as f: diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 index ad7807de..04907e15 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.ps1 @@ -1,4 +1,4 @@ -# db-load-xml v1.6 — Load 1C configuration from XML files +# db-load-xml v1.7 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills <# .SYNOPSIS @@ -192,12 +192,29 @@ try { exit 1 } if ($Mode -eq "Partial" -or $Files -or $ListFile) { - Write-Host "Error: ibcmd config import supports full-directory import only; use 1cv8 for partial/file lists" -ForegroundColor Red - exit 1 + # partial: import specific files (relative to ConfigDir) + $fileList = @() + if ($ListFile) { + if (-not (Test-Path $ListFile)) { + Write-Host "Error: list file not found: $ListFile" -ForegroundColor Red + exit 1 + } + $fileList = @(Get-Content -Path $ListFile -Encoding UTF8 | ForEach-Object { $_.Trim() } | Where-Object { $_ }) + } elseif ($Files) { + $fileList = @($Files -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) + } + if ($fileList.Count -eq 0) { + Write-Host "Error: -Files or -ListFile required for partial import" -ForegroundColor Red + exit 1 + } + $arguments = @("infobase", "config", "import", "files") + $fileList + $arguments += "--base-dir=$ConfigDir", "--db-path=$InfoBasePath" + if ($Extension) { $arguments += "--extension=$Extension" } + } else { + $arguments = @("infobase", "config", "import", "--db-path=$InfoBasePath") + if ($Extension) { $arguments += "--extension=$Extension" } + $arguments += "$ConfigDir" } - $arguments = @("infobase", "config", "import", "--db-path=$InfoBasePath") - if ($Extension) { $arguments += "--extension=$Extension" } - $arguments += "$ConfigDir" Write-Host "Running: ibcmd $($arguments -join ' ')" $output = & $V8Path @arguments 2>&1 $exitCode = $LASTEXITCODE diff --git a/.claude/skills/db-load-xml/scripts/db-load-xml.py b/.claude/skills/db-load-xml/scripts/db-load-xml.py index ef9b7b9b..1ce4b15e 100644 --- a/.claude/skills/db-load-xml/scripts/db-load-xml.py +++ b/.claude/skills/db-load-xml/scripts/db-load-xml.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# db-load-xml v1.6 — Load 1C configuration from XML files +# db-load-xml v1.7 — Load 1C configuration from XML files # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -136,12 +136,29 @@ def main(): print("Error: ibcmd config import does not support -AllExtensions (use -Extension or 1cv8)", file=sys.stderr) sys.exit(1) if args.Mode == "Partial" or args.Files or args.ListFile: - print("Error: ibcmd config import supports full-directory import only; use 1cv8 for partial/file lists", file=sys.stderr) - sys.exit(1) - arguments = ["infobase", "config", "import", f"--db-path={args.InfoBasePath}"] - if args.Extension: - arguments.append(f"--extension={args.Extension}") - arguments.append(args.ConfigDir) + # partial: import specific files (relative to ConfigDir) + if args.ListFile: + if not os.path.isfile(args.ListFile): + print(f"Error: list file not found: {args.ListFile}", file=sys.stderr) + sys.exit(1) + with open(args.ListFile, encoding="utf-8-sig") as f: + file_list = [ln.strip() for ln in f if ln.strip()] + elif args.Files: + file_list = [p.strip() for p in args.Files.split(",") if p.strip()] + else: + file_list = [] + if not file_list: + print("Error: -Files or -ListFile required for partial import", file=sys.stderr) + sys.exit(1) + arguments = ["infobase", "config", "import", "files"] + file_list + arguments += [f"--base-dir={args.ConfigDir}", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + else: + arguments = ["infobase", "config", "import", f"--db-path={args.InfoBasePath}"] + if args.Extension: + arguments.append(f"--extension={args.Extension}") + arguments.append(args.ConfigDir) print(f"Running: ibcmd {' '.join(arguments)}") result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace") if result.returncode != 0: