fix(epf-build): проверка исходников не видела модулей и форм

Относительный путь при копировании содержимого объекта в конфигурацию-заглушку
считался через Substring по длине переданной строки. Каталог может прийти с
коротким именем (C:\Users\NSHIRO~1\...), а Get-ChildItem отдаёт полное — разница
в один символ, и файлы уезжали в <Объект>\а\Ext\ObjectModule.bsl. Проверка при
этом молча шла по объекту без модулей и форм и всегда была зелёной. Длина
берётся у разрешённого пути; py-порт иммунен (os.path.relpath).

Дефект нашли новые кейсы stub-db-create — конвертация внешней обработки в объект
конфигурации: корневой тег и порождаемые типы, перевыпуск GUID, копирование .bsl
байт в байт. Каждый сверен возвратом дефекта в обоих портах.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013MQkqXxErBepYmoUycfkbn
This commit is contained in:
Nick Shirokov
2026-09-05 19:10:58 +03:00
co-authored by Claude Opus 5
parent 368d6bb278
commit 06bdee3e25
6 changed files with 189 additions and 4 deletions
@@ -1,4 +1,4 @@
# stub-db-create v1.9 — Create temp 1C infobase with metadata stubs for EPF/ERF build # stub-db-create v1.10 — Create temp 1C infobase with metadata stubs for EPF/ERF build
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)]
@@ -442,9 +442,13 @@ function Add-SourceObjectToConfig {
# Содержимое объекта — как есть; в XML та же подстановка типа, .bsl копируются байт в байт. # Содержимое объекта — как есть; в XML та же подстановка типа, .bsl копируются байт в байт.
$srcContent = Join-Path (Split-Path $SourceXml -Parent) $name $srcContent = Join-Path (Split-Path $SourceXml -Parent) $name
if (Test-Path $srcContent) { if (Test-Path $srcContent) {
# Длину префикса берём у РАЗРЕШЁННОГО пути, а не у переданной строки: путь может
# прийти с коротким именем (C:\Users\NSHIRO~1\…), а Get-ChildItem отдаёт полное — тогда
# отрезание по длине исходной строки оставляет в относительном пути чужие символы.
$srcRoot = (Get-Item -LiteralPath $srcContent).FullName.TrimEnd('\', '/')
$dstContent = Join-Path $objDir $name $dstContent = Join-Path $objDir $name
foreach ($f in (Get-ChildItem -Path $srcContent -Recurse -File)) { foreach ($f in (Get-ChildItem -LiteralPath $srcRoot -Recurse -File)) {
$rel = $f.FullName.Substring($srcContent.Length).TrimStart('\', '/') $rel = $f.FullName.Substring($srcRoot.Length).TrimStart('\', '/')
$dst = Join-Path $dstContent $rel $dst = Join-Path $dstContent $rel
New-Item -ItemType Directory -Path (Split-Path $dst -Parent) -Force | Out-Null New-Item -ItemType Directory -Path (Split-Path $dst -Parent) -Force | Out-Null
if ($f.Extension -ieq '.xml') { if ($f.Extension -ieq '.xml') {
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# stub-db-create v1.9 — Create temp 1C infobase with metadata stubs for EPF/ERF build # stub-db-create v1.10 — Create temp 1C infobase with metadata stubs for EPF/ERF build
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse import argparse
@@ -0,0 +1,5 @@
{
"script": "epf-build/scripts/stub-db-create",
"setup": "none",
"args": []
}
@@ -0,0 +1,64 @@
{
"name": "Внешняя обработка конвертируется в объект конфигурации",
"osOnly": "win32",
"fakePlatform": {
"exit": 1,
"log": ""
},
"preRun": [
{
"writeFile": {
"path": "src/Проба.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" xmlns:v8=\"http://v8.1c.ru/8.1/data/core\" xmlns:xr=\"http://v8.1c.ru/8.3/xcf/readable\" version=\"2.17\">\n\t<ExternalDataProcessor uuid=\"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb\">\n\t\t<InternalInfo>\n\t\t\t<xr:GeneratedType name=\"ExternalDataProcessorObject.Проба\" category=\"Object\">\n\t\t\t\t<xr:TypeId>cccccccc-4444-5555-6666-dddddddddddd</xr:TypeId>\n\t\t\t\t<xr:ValueId>eeeeeeee-7777-8888-9999-ffffffffffff</xr:ValueId>\n\t\t\t</xr:GeneratedType>\n\t\t</InternalInfo>\n\t\t<Properties>\n\t\t\t<Name>Проба</Name>\n\t\t\t<DefaultForm>ExternalDataProcessor.Проба.Form.Форма</DefaultForm>\n\t\t</Properties>\n\t\t<ChildObjects>\n\t\t\t<Form>Форма</Form>\n\t\t</ChildObjects>\n\t</ExternalDataProcessor>\n</MetaDataObject>\n"
}
},
{
"writeFile": {
"path": "src/Проба/Ext/ObjectModule.bsl",
"content": "Процедура Проба()\r\n\tСообщить(\"ExternalDataProcessorObject.Проба\");\r\n\tСообщить(\"ExternalDataProcessor.Проба.Form.Форма\");\r\nКонецПроцедуры\r\n"
}
},
{
"writeFile": {
"path": "src/Проба/Forms/Форма.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.17\">\n\t<Form uuid=\"11111111-2222-3333-4444-555555555555\">\n\t\t<Properties>\n\t\t\t<Name>Форма</Name>\n\t\t</Properties>\n\t</Form>\n</MetaDataObject>\n"
}
}
],
"args_extra": [
"-SourceDir",
"{workDir}\\src",
"-V8Path",
"{workDir}\\fake.cmd",
"-TempBasePath",
"{workDir}\\base",
"-EmbedSourceFile",
"{workDir}\\src\\Проба.xml"
],
"expect": {
"fileContains": [
{
"file": "base\\cfg\\DataProcessors\\Проба.xml",
"text": [
"<DataProcessor uuid=",
"<xr:GeneratedType name=\"DataProcessorObject.Проба\" category=\"Object\">",
"<xr:GeneratedType name=\"DataProcessorManager.Проба\" category=\"Manager\">",
"<DefaultForm>DataProcessor.Проба.Form.Форма</DefaultForm>"
]
},
{
"file": "base\\cfg\\Configuration.xml",
"text": "<DataProcessor>Проба</DataProcessor>"
}
],
"fileNotContains": {
"file": "base\\cfg\\DataProcessors\\Проба.xml",
"text": [
"<ExternalDataProcessor",
"ExternalDataProcessorObject."
]
}
},
"expectError": true,
"noSnapshot": "платформа фейковая: проверяется сгенерированная конфигурация, а не база"
}
@@ -0,0 +1,52 @@
{
"name": "Модуль копируется байт в байт",
"osOnly": "win32",
"fakePlatform": {
"exit": 1,
"log": ""
},
"preRun": [
{
"writeFile": {
"path": "src/Проба.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" xmlns:v8=\"http://v8.1c.ru/8.1/data/core\" xmlns:xr=\"http://v8.1c.ru/8.3/xcf/readable\" version=\"2.17\">\n\t<ExternalDataProcessor uuid=\"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb\">\n\t\t<InternalInfo>\n\t\t\t<xr:GeneratedType name=\"ExternalDataProcessorObject.Проба\" category=\"Object\">\n\t\t\t\t<xr:TypeId>cccccccc-4444-5555-6666-dddddddddddd</xr:TypeId>\n\t\t\t\t<xr:ValueId>eeeeeeee-7777-8888-9999-ffffffffffff</xr:ValueId>\n\t\t\t</xr:GeneratedType>\n\t\t</InternalInfo>\n\t\t<Properties>\n\t\t\t<Name>Проба</Name>\n\t\t\t<DefaultForm>ExternalDataProcessor.Проба.Form.Форма</DefaultForm>\n\t\t</Properties>\n\t\t<ChildObjects>\n\t\t\t<Form>Форма</Form>\n\t\t</ChildObjects>\n\t</ExternalDataProcessor>\n</MetaDataObject>\n"
}
},
{
"writeFile": {
"path": "src/Проба/Ext/ObjectModule.bsl",
"content": "Процедура Проба()\r\n\tСообщить(\"ExternalDataProcessorObject.Проба\");\r\n\tСообщить(\"ExternalDataProcessor.Проба.Form.Форма\");\r\nКонецПроцедуры\r\n"
}
},
{
"writeFile": {
"path": "src/Проба/Forms/Форма.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.17\">\n\t<Form uuid=\"11111111-2222-3333-4444-555555555555\">\n\t\t<Properties>\n\t\t\t<Name>Форма</Name>\n\t\t</Properties>\n\t</Form>\n</MetaDataObject>\n"
}
}
],
"args_extra": [
"-SourceDir",
"{workDir}\\src",
"-V8Path",
"{workDir}\\fake.cmd",
"-TempBasePath",
"{workDir}\\base",
"-EmbedSourceFile",
"{workDir}\\src\\Проба.xml"
],
"expect": {
"filesEqual": [
{
"actual": "base/cfg/DataProcessors/Проба/Ext/ObjectModule.bsl",
"expected": "src/Проба/Ext/ObjectModule.bsl"
}
],
"fileContains": {
"file": "base\\cfg\\DataProcessors\\Проба\\Ext\\ObjectModule.bsl",
"text": "ExternalDataProcessorObject.Проба"
}
},
"expectError": true,
"noSnapshot": "проверяется равенство файлов, а не снэпшот"
}
@@ -0,0 +1,60 @@
{
"name": "У копии все GUID свои",
"osOnly": "win32",
"fakePlatform": {
"exit": 1,
"log": ""
},
"preRun": [
{
"writeFile": {
"path": "src/Проба.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" xmlns:v8=\"http://v8.1c.ru/8.1/data/core\" xmlns:xr=\"http://v8.1c.ru/8.3/xcf/readable\" version=\"2.17\">\n\t<ExternalDataProcessor uuid=\"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb\">\n\t\t<InternalInfo>\n\t\t\t<xr:GeneratedType name=\"ExternalDataProcessorObject.Проба\" category=\"Object\">\n\t\t\t\t<xr:TypeId>cccccccc-4444-5555-6666-dddddddddddd</xr:TypeId>\n\t\t\t\t<xr:ValueId>eeeeeeee-7777-8888-9999-ffffffffffff</xr:ValueId>\n\t\t\t</xr:GeneratedType>\n\t\t</InternalInfo>\n\t\t<Properties>\n\t\t\t<Name>Проба</Name>\n\t\t\t<DefaultForm>ExternalDataProcessor.Проба.Form.Форма</DefaultForm>\n\t\t</Properties>\n\t\t<ChildObjects>\n\t\t\t<Form>Форма</Form>\n\t\t</ChildObjects>\n\t</ExternalDataProcessor>\n</MetaDataObject>\n"
}
},
{
"writeFile": {
"path": "src/Проба/Ext/ObjectModule.bsl",
"content": "Процедура Проба()\r\n\tСообщить(\"ExternalDataProcessorObject.Проба\");\r\n\tСообщить(\"ExternalDataProcessor.Проба.Form.Форма\");\r\nКонецПроцедуры\r\n"
}
},
{
"writeFile": {
"path": "src/Проба/Forms/Форма.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.17\">\n\t<Form uuid=\"11111111-2222-3333-4444-555555555555\">\n\t\t<Properties>\n\t\t\t<Name>Форма</Name>\n\t\t</Properties>\n\t</Form>\n</MetaDataObject>\n"
}
}
],
"args_extra": [
"-SourceDir",
"{workDir}\\src",
"-V8Path",
"{workDir}\\fake.cmd",
"-TempBasePath",
"{workDir}\\base",
"-EmbedSourceFile",
"{workDir}\\src\\Проба.xml"
],
"expect": {
"fileNotContains": [
{
"file": "base\\cfg\\DataProcessors\\Проба.xml",
"text": [
"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb",
"cccccccc-4444-5555-6666-dddddddddddd",
"eeeeeeee-7777-8888-9999-ffffffffffff"
]
},
{
"file": "base\\cfg\\DataProcessors\\Проба\\Forms\\Форма.xml",
"text": "11111111-2222-3333-4444-555555555555"
}
],
"fileContains": {
"file": "base\\cfg\\DataProcessors\\Проба.xml",
"text": "<xr:TypeId>"
}
},
"expectError": true,
"noSnapshot": "генерируются случайные GUID — снять эталон нельзя"
}