mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-26 12:05:52 +03:00
feat(epf-build): общие модули конфигурации в проверке исходников через configSrc
Проверка исходников идёт в конфигурации-заглушке, где общих модулей не было: обработка с кодом БСП не собиралась без -Checks off. - stub-db-create -ConfigSrc: общие модули, к которым обращается код, получают пустых двойников с флагами контекста из выгрузки; неизвестные имена не угадываются - epf-build -ConfigSrc, по умолчанию configSrc базы из .v8-project.json - подсказки к «Переменная не определена (X)»: модуль не в том контексте / модуля нет в configSrc / выгрузка не передана (с -ConfigSrc и -Checks off) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b43d4050a6
commit
636344666d
@@ -58,6 +58,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <п
|
|||||||
| `-OutputFile <путь>` | да | Путь к выходному EPF/ERF-файлу |
|
| `-OutputFile <путь>` | да | Путь к выходному EPF/ERF-файлу |
|
||||||
| `-Checks <список>` | нет | Что проверить перед сборкой: `modules`, `handlers`, `unreferenced`, `empty-handlers`, `config`; `off` — не проверять. По умолчанию `modules,handlers` |
|
| `-Checks <список>` | нет | Что проверить перед сборкой: `modules`, `handlers`, `unreferenced`, `empty-handlers`, `config`; `off` — не проверять. По умолчанию `modules,handlers` |
|
||||||
| `-Context <список>` | нет | Контексты проверки `modules`: `ThinClient`, `Server`, `ExternalConnection`, `ThickClientOrdinaryApplication`. По умолчанию `ThinClient,Server` |
|
| `-Context <список>` | нет | Контексты проверки `modules`: `ThinClient`, `Server`, `ExternalConnection`, `ThickClientOrdinaryApplication`. По умолчанию `ThinClient,Server` |
|
||||||
|
| `-ConfigSrc <путь>` | нет | Каталог XML-выгрузки конфигурации, в которой будет работать обработка. По умолчанию — `configSrc` указанной базы из `.v8-project.json` |
|
||||||
| `-AdditionalV8Arguments <список>` | нет | Доп. аргументы запуска `1cv8.exe` через запятую, напр. `/UseHwLicenses+` |
|
| `-AdditionalV8Arguments <список>` | нет | Доп. аргументы запуска `1cv8.exe` через запятую, напр. `/UseHwLicenses+` |
|
||||||
| `-AdditionalIbcmdArguments <список>` | нет | Доп. аргументы `ibcmd` через запятую, в форме `--ключ=значение` |
|
| `-AdditionalIbcmdArguments <список>` | нет | Доп. аргументы `ibcmd` через запятую, в форме `--ключ=значение` |
|
||||||
|
|
||||||
@@ -72,6 +73,12 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <п
|
|||||||
|
|
||||||
Проверка идёт на отдельной временной базе, даже если база указана: чужую конфигурацию навык не трогает.
|
Проверка идёт на отдельной временной базе, даже если база указана: чужую конфигурацию навык не трогает.
|
||||||
|
|
||||||
|
Общие модули конфигурации (`ОбщегоНазначения`, `УправлениеПечатью` и т.п.) проверка видит только
|
||||||
|
при известной выгрузке конфигурации — `-ConfigSrc` или `configSrc` базы в `.v8-project.json`.
|
||||||
|
Без неё обращения к ним — ошибка «Переменная не определена»; тогда укажи выгрузку или собери
|
||||||
|
с `-Checks off`. Методы глобальных общих модулей, вызванные без имени модуля, проверка не видит
|
||||||
|
и с выгрузкой — для такого кода остаётся `-Checks off`.
|
||||||
|
|
||||||
## Примеры
|
## Примеры
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# epf-build v1.19 — Build external data processor or report (EPF/ERF) from XML sources
|
# epf-build v1.20 — Build external data processor or report (EPF/ERF) from XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
@@ -33,6 +33,9 @@
|
|||||||
.PARAMETER OutputFile
|
.PARAMETER OutputFile
|
||||||
Путь к выходному EPF/ERF-файлу
|
Путь к выходному EPF/ERF-файлу
|
||||||
|
|
||||||
|
.PARAMETER ConfigSrc
|
||||||
|
Каталог XML-выгрузки целевой конфигурации (общие модули для проверки исходников)
|
||||||
|
|
||||||
.PARAMETER AdditionalV8Arguments
|
.PARAMETER AdditionalV8Arguments
|
||||||
Дополнительные аргументы запуска 1cv8.exe (например /UseHwLicenses+)
|
Дополнительные аргументы запуска 1cv8.exe (например /UseHwLicenses+)
|
||||||
|
|
||||||
@@ -80,6 +83,10 @@ param(
|
|||||||
# Контексты синтаксической проверки. По умолчанию ThinClient,Server.
|
# Контексты синтаксической проверки. По умолчанию ThinClient,Server.
|
||||||
[Parameter(Mandatory=$false)]
|
[Parameter(Mandatory=$false)]
|
||||||
[string]$Context,
|
[string]$Context,
|
||||||
|
# Выгрузка конфигурации, в которой будет работать обработка: её общие модули видны проверке.
|
||||||
|
# Без параметра берётся configSrc базы из .v8-project.json.
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]$ConfigSrc,
|
||||||
|
|
||||||
[Parameter(Mandatory=$false)]
|
[Parameter(Mandatory=$false)]
|
||||||
[string[]]$AdditionalV8Arguments = @(),
|
[string[]]$AdditionalV8Arguments = @(),
|
||||||
@@ -262,6 +269,7 @@ $V8Path = ConvertTo-CleanPath $V8Path '-V8Path'
|
|||||||
$InfoBasePath = ConvertTo-CleanPath $InfoBasePath '-InfoBasePath'
|
$InfoBasePath = ConvertTo-CleanPath $InfoBasePath '-InfoBasePath'
|
||||||
$SourceFile = ConvertTo-CleanPath $SourceFile '-SourceFile'
|
$SourceFile = ConvertTo-CleanPath $SourceFile '-SourceFile'
|
||||||
$OutputFile = ConvertTo-CleanPath $OutputFile '-OutputFile'
|
$OutputFile = ConvertTo-CleanPath $OutputFile '-OutputFile'
|
||||||
|
$ConfigSrc = ConvertTo-CleanPath $ConfigSrc '-ConfigSrc'
|
||||||
|
|
||||||
function Assert-InfoBaseExists {
|
function Assert-InfoBaseExists {
|
||||||
# These skills work on a ready infobase. Saying so up front beats the platform's
|
# These skills work on a ready infobase. Saying so up front beats the platform's
|
||||||
@@ -481,6 +489,24 @@ function Resolve-SourcePath {
|
|||||||
return $null
|
return $null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# «Переменная не определена (X)» при обращении X.… — чаще всего общий модуль конфигурации, которого
|
||||||
|
# проверке не показали. Платформа печатает строку кода следующей строкой лога с меткой <<?>> перед X.
|
||||||
|
# Подсказка одна на имя; сама ошибка остаётся ошибкой.
|
||||||
|
function Get-UndefinedModuleHint {
|
||||||
|
param([string]$Line, [string]$CodeLine, $Hinted)
|
||||||
|
$m = [regex]::Match($Line, 'Переменная не определена \(([^)]+)\)')
|
||||||
|
if (-not $m.Success) { return $null }
|
||||||
|
$name = $m.Groups[1].Value
|
||||||
|
if (-not [regex]::IsMatch($CodeLine, '<<\?>>\s*' + [regex]::Escape($name) + '\s*\.')) { return $null }
|
||||||
|
if (-not $Hinted.Add($name)) { return $null }
|
||||||
|
if (-not $checkConfigSrc) { return "похоже на общий модуль конфигурации — выгрузка конфигурации проверке не передана" }
|
||||||
|
$cmDir = Join-Path $checkConfigSrc "CommonModules"
|
||||||
|
$inCfg = (Test-Path -LiteralPath $cmDir -PathType Container) -and
|
||||||
|
@(Get-ChildItem -LiteralPath $cmDir -Filter "*.xml" -File | Where-Object { $_.BaseName.Equals($name, [StringComparison]::OrdinalIgnoreCase) }).Count -gt 0
|
||||||
|
if ($inCfg) { return "общий модуль $name есть в configSrc, но недоступен в контексте проверки (см. «Проверка: …» в строке выше)" }
|
||||||
|
return "общего модуля $name нет в configSrc ($checkConfigSrc)"
|
||||||
|
}
|
||||||
|
|
||||||
# $true, если платформа нашла проблемы — вызывающий не собирает артефакт.
|
# $true, если платформа нашла проблемы — вызывающий не собирает артефакт.
|
||||||
function Invoke-SourceCheck {
|
function Invoke-SourceCheck {
|
||||||
param([string]$Exe, [string]$BasePath, [string[]]$Flags, [string]$SourceDir, [string[]]$ExtraArgs)
|
param([string]$Exe, [string]$BasePath, [string[]]$Flags, [string]$SourceDir, [string[]]$ExtraArgs)
|
||||||
@@ -508,10 +534,19 @@ function Invoke-SourceCheck {
|
|||||||
Write-Host "Error: платформа нашла проблемы в исходниках — сборка отменена" -ForegroundColor Red
|
Write-Host "Error: платформа нашла проблемы в исходниках — сборка отменена" -ForegroundColor Red
|
||||||
# Пустой лог при ненулевом коде — отказ не по находкам (база занята, нет лицензии); молчать нельзя.
|
# Пустой лог при ненулевом коде — отказ не по находкам (база занята, нет лицензии); молчать нельзя.
|
||||||
if ($lines.Count -eq 0) { Write-Host " платформа вернула код $($res.ExitCode) без сообщений" -ForegroundColor Red }
|
if ($lines.Count -eq 0) { Write-Host " платформа вернула код $($res.ExitCode) без сообщений" -ForegroundColor Red }
|
||||||
foreach ($l in $lines) {
|
$hinted = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase)
|
||||||
|
for ($i = 0; $i -lt $lines.Count; $i++) {
|
||||||
|
$l = $lines[$i]
|
||||||
Write-Host " $($l.TrimEnd())" -ForegroundColor Red
|
Write-Host " $($l.TrimEnd())" -ForegroundColor Red
|
||||||
$srcPath = Resolve-SourcePath $l $SourceDir
|
$srcPath = Resolve-SourcePath $l $SourceDir
|
||||||
if ($srcPath) { Write-Host " -> $srcPath" -ForegroundColor Red }
|
if ($srcPath) { Write-Host " -> $srcPath" -ForegroundColor Red }
|
||||||
|
# Подсказка — под строкой кода, которую платформа печатает следом за ошибкой.
|
||||||
|
$hint = if ($i -gt 0) { Get-UndefinedModuleHint $lines[$i - 1] $l $hinted } else { $null }
|
||||||
|
if ($hint) { Write-Host " [hint] $hint" -ForegroundColor Yellow }
|
||||||
|
}
|
||||||
|
if ($hinted.Count -gt 0 -and -not $checkConfigSrc) {
|
||||||
|
Write-Host "[hint] Общие модули конфигурации проверке не видны: $(@($hinted) -join ', ')." -ForegroundColor Yellow
|
||||||
|
Write-Host " Укажите -ConfigSrc (каталог выгрузки конфигурации) или базу с configSrc в .v8-project.json; либо соберите без проверки: -Checks off" -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
return $true
|
return $true
|
||||||
} finally {
|
} finally {
|
||||||
@@ -566,6 +601,31 @@ elseif ($checkList.Count -gt 0 -and $checkList -notcontains 'modules') {
|
|||||||
}
|
}
|
||||||
$sourceDir = Split-Path $SourceFile -Parent
|
$sourceDir = Split-Path $SourceFile -Parent
|
||||||
|
|
||||||
|
# Выгрузка целевой конфигурации для проверки: явный -ConfigSrc, иначе configSrc базы из реестра.
|
||||||
|
# Без неё обращения к общим модулям конфигурации проверка считает неопределёнными переменными.
|
||||||
|
function Resolve-ConfigSrc {
|
||||||
|
if ($ConfigSrc) {
|
||||||
|
if (-not (Test-Path -LiteralPath $ConfigSrc -PathType Container)) {
|
||||||
|
Write-Host "Error: -ConfigSrc not found: $ConfigSrc" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
return (Resolve-Path -LiteralPath $ConfigSrc).Path
|
||||||
|
}
|
||||||
|
$db = Find-ProjectDatabase
|
||||||
|
if (-not $db -or -not $db.configSrc) { return $null }
|
||||||
|
$p = [string]$db.configSrc
|
||||||
|
if (-not [System.IO.Path]::IsPathRooted($p)) {
|
||||||
|
$pf = Find-V8Project (Get-Location).Path
|
||||||
|
$p = Join-Path (Split-Path $pf -Parent) $p
|
||||||
|
}
|
||||||
|
if (-not (Test-Path -LiteralPath $p -PathType Container)) {
|
||||||
|
Write-Host "WARNING: configSrc базы не найден: $p — общие модули конфигурации проверке недоступны" -ForegroundColor Yellow
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
return $p
|
||||||
|
}
|
||||||
|
$checkConfigSrc = if ($checkList.Count -gt 0) { Resolve-ConfigSrc } else { $null }
|
||||||
|
|
||||||
function New-StubBase {
|
function New-StubBase {
|
||||||
# Стаб запускает свои процессы платформы (CREATEINFOBASE, LoadConfigFromFiles, UpdateDBCfg) —
|
# Стаб запускает свои процессы платформы (CREATEINFOBASE, LoadConfigFromFiles, UpdateDBCfg) —
|
||||||
# им нужны те же дополнительные аргументы, что и сборке. Передаются только явные: файл проекта
|
# им нужны те же дополнительные аргументы, что и сборке. Передаются только явные: файл проекта
|
||||||
@@ -576,6 +636,7 @@ function New-StubBase {
|
|||||||
$q = { param($s) "'" + ($s -replace "'", "''") + "'" }
|
$q = { param($s) "'" + ($s -replace "'", "''") + "'" }
|
||||||
$stubCmd = "& $(& $q $stubScript) -SourceDir $(& $q $sourceDir) -V8Path $(& $q $V8Path) -TempBasePath $(& $q $BasePath)"
|
$stubCmd = "& $(& $q $stubScript) -SourceDir $(& $q $sourceDir) -V8Path $(& $q $V8Path) -TempBasePath $(& $q $BasePath)"
|
||||||
if ($Embed) { $stubCmd += " -EmbedSourceFile $(& $q $SourceFile)" }
|
if ($Embed) { $stubCmd += " -EmbedSourceFile $(& $q $SourceFile)" }
|
||||||
|
if ($Embed -and $checkConfigSrc) { $stubCmd += " -ConfigSrc $(& $q $checkConfigSrc)" }
|
||||||
if ($AdditionalV8Arguments.Count -gt 0) {
|
if ($AdditionalV8Arguments.Count -gt 0) {
|
||||||
$stubCmd += " -AdditionalV8Arguments " + (($AdditionalV8Arguments | ForEach-Object { & $q $_ }) -join ',')
|
$stubCmd += " -AdditionalV8Arguments " + (($AdditionalV8Arguments | ForEach-Object { & $q $_ }) -join ',')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# epf-build v1.19 — Build external data processor or report (EPF/ERF) from XML sources
|
# epf-build v1.20 — Build external data processor or report (EPF/ERF) from XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -513,7 +513,7 @@ def resolve_source_path(line, source_dir):
|
|||||||
|
|
||||||
|
|
||||||
# True, если платформа нашла проблемы — вызывающий не собирает артефакт.
|
# True, если платформа нашла проблемы — вызывающий не собирает артефакт.
|
||||||
def invoke_source_check(exe, base_path, flags, source_dir, extra_args):
|
def invoke_source_check(exe, base_path, flags, source_dir, extra_args, config_src=None):
|
||||||
exe_dir = os.path.dirname(exe)
|
exe_dir = os.path.dirname(exe)
|
||||||
exe_leaf = os.path.basename(exe)
|
exe_leaf = os.path.basename(exe)
|
||||||
if exe_leaf.lower().startswith('ibcmd'):
|
if exe_leaf.lower().startswith('ibcmd'):
|
||||||
@@ -547,16 +547,73 @@ def invoke_source_check(exe, base_path, flags, source_dir, extra_args):
|
|||||||
# Пустой лог при ненулевом коде — отказ не по находкам (база занята, нет лицензии); молчать нельзя.
|
# Пустой лог при ненулевом коде — отказ не по находкам (база занята, нет лицензии); молчать нельзя.
|
||||||
if not lines:
|
if not lines:
|
||||||
print(f' платформа вернула код {result.returncode} без сообщений')
|
print(f' платформа вернула код {result.returncode} без сообщений')
|
||||||
for l in lines:
|
hinted = []
|
||||||
|
for i, l in enumerate(lines):
|
||||||
print(f' {l.rstrip()}')
|
print(f' {l.rstrip()}')
|
||||||
src_path = resolve_source_path(l, source_dir)
|
src_path = resolve_source_path(l, source_dir)
|
||||||
if src_path:
|
if src_path:
|
||||||
print(f' -> {src_path}')
|
print(f' -> {src_path}')
|
||||||
|
# Подсказка — под строкой кода, которую платформа печатает следом за ошибкой.
|
||||||
|
hint = get_undefined_module_hint(lines[i - 1], l, hinted, config_src) if i > 0 else None
|
||||||
|
if hint:
|
||||||
|
print(f' [hint] {hint}')
|
||||||
|
if hinted and not config_src:
|
||||||
|
print('[hint] \u041e\u0431\u0449\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u043d\u0435 \u0432\u0438\u0434\u043d\u044b: %s.' % ', '.join(hinted))
|
||||||
|
print(' \u0423\u043a\u0430\u0436\u0438\u0442\u0435 -ConfigSrc (\u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438) \u0438\u043b\u0438 \u0431\u0430\u0437\u0443 \u0441 configSrc \u0432 .v8-project.json; \u043b\u0438\u0431\u043e \u0441\u043e\u0431\u0435\u0440\u0438\u0442\u0435 \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438: -Checks off')
|
||||||
return True
|
return True
|
||||||
finally:
|
finally:
|
||||||
shutil.rmtree(d, ignore_errors=True)
|
shutil.rmtree(d, ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
|
# Выгрузка целевой конфигурации для проверки: явный -ConfigSrc, иначе configSrc базы из реестра.
|
||||||
|
# Без неё обращения к общим модулям конфигурации проверка считает неопределёнными переменными.
|
||||||
|
def resolve_config_src(args):
|
||||||
|
if args.ConfigSrc:
|
||||||
|
if not os.path.isdir(args.ConfigSrc):
|
||||||
|
print('Error: -ConfigSrc not found: %s' % args.ConfigSrc)
|
||||||
|
sys.exit(1)
|
||||||
|
return os.path.abspath(args.ConfigSrc)
|
||||||
|
db = find_project_database(args)
|
||||||
|
if not db or not db.get('configSrc'):
|
||||||
|
return None
|
||||||
|
p = str(db['configSrc'])
|
||||||
|
# Реестр пишут и на Windows: относительный путь может прийти с обратными слешами.
|
||||||
|
if os.sep == '/':
|
||||||
|
p = p.replace('\\', '/')
|
||||||
|
if not os.path.isabs(p):
|
||||||
|
pf = _sg_find_v8project(os.getcwd())
|
||||||
|
p = os.path.join(os.path.dirname(pf), p)
|
||||||
|
if not os.path.isdir(p):
|
||||||
|
print('WARNING: configSrc \u0431\u0430\u0437\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d: %s \u2014 \u043e\u0431\u0449\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b' % p)
|
||||||
|
return None
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
# «Переменная не определена (X)» при обращении X.… — чаще всего общий модуль конфигурации, которого
|
||||||
|
# проверке не показали. Платформа печатает строку кода следующей строкой лога с меткой <<?>> перед X.
|
||||||
|
# Подсказка одна на имя; сама ошибка остаётся ошибкой.
|
||||||
|
def get_undefined_module_hint(line, code_line, hinted, config_src):
|
||||||
|
m = re.search(r'\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \(([^)]+)\)', line)
|
||||||
|
if not m:
|
||||||
|
return None
|
||||||
|
name = m.group(1)
|
||||||
|
if not re.search(r'<<\?>>\s*' + re.escape(name) + r'\s*\.', code_line):
|
||||||
|
return None
|
||||||
|
if any(h.casefold() == name.casefold() for h in hinted):
|
||||||
|
return None
|
||||||
|
hinted.append(name)
|
||||||
|
if not config_src:
|
||||||
|
return '\u043f\u043e\u0445\u043e\u0436\u0435 \u043d\u0430 \u043e\u0431\u0449\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u2014 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430'
|
||||||
|
cm_dir = os.path.join(config_src, 'CommonModules')
|
||||||
|
in_cfg = os.path.isdir(cm_dir) and any(
|
||||||
|
f.lower().endswith('.xml') and os.path.splitext(f)[0].casefold() == name.casefold()
|
||||||
|
and os.path.isfile(os.path.join(cm_dir, f))
|
||||||
|
for f in os.listdir(cm_dir))
|
||||||
|
if in_cfg:
|
||||||
|
return '\u043e\u0431\u0449\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c %s \u0435\u0441\u0442\u044c \u0432 configSrc, \u043d\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 (\u0441\u043c. \u00ab\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430: \u2026\u00bb \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u044b\u0448\u0435)' % name
|
||||||
|
return '\u043e\u0431\u0449\u0435\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f %s \u043d\u0435\u0442 \u0432 configSrc (%s)' % (name, config_src)
|
||||||
|
|
||||||
|
|
||||||
# Проверять ли исходники: -Checks off сильнее настройки проекта externalCheck.
|
# Проверять ли исходники: -Checks off сильнее настройки проекта externalCheck.
|
||||||
def get_source_check_list(checks):
|
def get_source_check_list(checks):
|
||||||
known = ['modules', 'handlers', 'unreferenced', 'empty-handlers', 'config']
|
known = ['modules', 'handlers', 'unreferenced', 'empty-handlers', 'config']
|
||||||
@@ -601,6 +658,9 @@ def main():
|
|||||||
parser.add_argument("-Checks", default="")
|
parser.add_argument("-Checks", default="")
|
||||||
# Контексты синтаксической проверки. По умолчанию ThinClient,Server.
|
# Контексты синтаксической проверки. По умолчанию ThinClient,Server.
|
||||||
parser.add_argument("-Context", default="")
|
parser.add_argument("-Context", default="")
|
||||||
|
# Выгрузка конфигурации, в которой будет работать обработка: её общие модули видны проверке.
|
||||||
|
# Без параметра берётся configSrc базы из .v8-project.json.
|
||||||
|
parser.add_argument("-ConfigSrc", default="")
|
||||||
parser.add_argument("-AdditionalV8Arguments", nargs="*", default=[],
|
parser.add_argument("-AdditionalV8Arguments", nargs="*", default=[],
|
||||||
help="Extra 1cv8 arguments, e.g. /UseHwLicenses+")
|
help="Extra 1cv8 arguments, e.g. /UseHwLicenses+")
|
||||||
parser.add_argument("-AdditionalIbcmdArguments", nargs="*", default=[],
|
parser.add_argument("-AdditionalIbcmdArguments", nargs="*", default=[],
|
||||||
@@ -614,6 +674,7 @@ def main():
|
|||||||
assert_infobase_exists(args.InfoBasePath)
|
assert_infobase_exists(args.InfoBasePath)
|
||||||
args.SourceFile = clean_path(args.SourceFile, "-SourceFile")
|
args.SourceFile = clean_path(args.SourceFile, "-SourceFile")
|
||||||
args.OutputFile = clean_path(args.OutputFile, "-OutputFile")
|
args.OutputFile = clean_path(args.OutputFile, "-OutputFile")
|
||||||
|
args.ConfigSrc = clean_path(args.ConfigSrc, "-ConfigSrc")
|
||||||
|
|
||||||
# --- Resolve V8Path ---
|
# --- Resolve V8Path ---
|
||||||
v8path = resolve_v8path(args.V8Path, args)
|
v8path = resolve_v8path(args.V8Path, args)
|
||||||
@@ -643,6 +704,7 @@ def main():
|
|||||||
print('Error: -Context задан, но в -Checks нет modules — контексты относятся только к ней')
|
print('Error: -Context задан, но в -Checks нет modules — контексты относятся только к ней')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
source_dir = os.path.dirname(os.path.abspath(args.SourceFile))
|
source_dir = os.path.dirname(os.path.abspath(args.SourceFile))
|
||||||
|
check_config_src = resolve_config_src(args) if check_list else None
|
||||||
|
|
||||||
def new_stub_base(base_path, embed):
|
def new_stub_base(base_path, embed):
|
||||||
# The stub runs its own platform processes (CREATEINFOBASE, LoadConfigFromFiles,
|
# The stub runs its own platform processes (CREATEINFOBASE, LoadConfigFromFiles,
|
||||||
@@ -653,6 +715,8 @@ def main():
|
|||||||
"-TempBasePath", base_path]
|
"-TempBasePath", base_path]
|
||||||
if embed:
|
if embed:
|
||||||
stub_cmd += ["-EmbedSourceFile", args.SourceFile]
|
stub_cmd += ["-EmbedSourceFile", args.SourceFile]
|
||||||
|
if embed and check_config_src:
|
||||||
|
stub_cmd += ["-ConfigSrc", check_config_src]
|
||||||
if v8_extra:
|
if v8_extra:
|
||||||
stub_cmd += ["-AdditionalV8Arguments"] + list(v8_extra)
|
stub_cmd += ["-AdditionalV8Arguments"] + list(v8_extra)
|
||||||
if ibcmd_extra:
|
if ibcmd_extra:
|
||||||
@@ -700,7 +764,8 @@ def main():
|
|||||||
# Проверку ведёт 1cv8, поэтому ibcmd-шные дополнительные аргументы ей не отдаём.
|
# Проверку ведёт 1cv8, поэтому ibcmd-шные дополнительные аргументы ей не отдаём.
|
||||||
check_extra = [] if engine == "ibcmd" else extra_args
|
check_extra = [] if engine == "ibcmd" else extra_args
|
||||||
found = invoke_source_check(v8path, check_base_path,
|
found = invoke_source_check(v8path, check_base_path,
|
||||||
get_check_flags(check_list, context_list), source_dir, check_extra)
|
get_check_flags(check_list, context_list), source_dir, check_extra,
|
||||||
|
check_config_src)
|
||||||
if found:
|
if found:
|
||||||
if auto_created_base and os.path.exists(auto_created_base):
|
if auto_created_base and os.path.exists(auto_created_base):
|
||||||
shutil.rmtree(auto_created_base, ignore_errors=True)
|
shutil.rmtree(auto_created_base, ignore_errors=True)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# stub-db-create v1.11 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
# stub-db-create v1.12 — 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)]
|
||||||
@@ -13,6 +13,10 @@ param(
|
|||||||
# смогла проверить его штатными проверками. Без параметра стаб работает как раньше.
|
# смогла проверить его штатными проверками. Без параметра стаб работает как раньше.
|
||||||
[string]$EmbedSourceFile,
|
[string]$EmbedSourceFile,
|
||||||
|
|
||||||
|
# Выгрузка целевой конфигурации: общие модули, к которым обращается код, получают в заглушке
|
||||||
|
# пустых двойников с настоящими флагами контекста.
|
||||||
|
[string]$ConfigSrc,
|
||||||
|
|
||||||
[string[]]$AdditionalV8Arguments = @(),
|
[string[]]$AdditionalV8Arguments = @(),
|
||||||
|
|
||||||
[string[]]$AdditionalIbcmdArguments = @()
|
[string[]]$AdditionalIbcmdArguments = @()
|
||||||
@@ -43,6 +47,7 @@ function ConvertTo-CleanPath {
|
|||||||
$SourceDir = ConvertTo-CleanPath $SourceDir '-SourceDir'
|
$SourceDir = ConvertTo-CleanPath $SourceDir '-SourceDir'
|
||||||
$V8Path = ConvertTo-CleanPath $V8Path '-V8Path'
|
$V8Path = ConvertTo-CleanPath $V8Path '-V8Path'
|
||||||
$TempBasePath = ConvertTo-CleanPath $TempBasePath '-TempBasePath'
|
$TempBasePath = ConvertTo-CleanPath $TempBasePath '-TempBasePath'
|
||||||
|
$ConfigSrc = ConvertTo-CleanPath $ConfigSrc '-ConfigSrc'
|
||||||
|
|
||||||
# --- Additional platform arguments ---
|
# --- Additional platform arguments ---
|
||||||
$script:V8OwnedKeys = @(
|
$script:V8OwnedKeys = @(
|
||||||
@@ -353,10 +358,67 @@ foreach ($f in $xmlFiles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --- 1c. Общие модули целевой конфигурации, к которым обращается код ---
|
||||||
|
# Проверка модулей (замер 8.3.24, 8.3.27) требует от общего модуля только двух вещей: чтобы он
|
||||||
|
# существовал и был доступен в контексте вызова. Методы, их экспорт и число параметров она не
|
||||||
|
# сверяет. Поэтому двойнику хватает имени и флагов контекста из настоящей выгрузки, тело пустое,
|
||||||
|
# и зависимости модуля за ним не тянутся. Двойник получает только имя, которое есть в выгрузке:
|
||||||
|
# неизвестное имя остаётся ошибкой проверки, а не угадывается.
|
||||||
|
|
||||||
|
# Код без строковых литералов и комментариев: слова в них — не обращения к модулям.
|
||||||
|
function Remove-BslNoise {
|
||||||
|
param([string]$Code)
|
||||||
|
$out = New-Object System.Text.StringBuilder
|
||||||
|
foreach ($line in ($Code -split "`r?`n")) {
|
||||||
|
# Продолжение многострочной строки («|ВЫБРАТЬ …»): литерал до закрывающей кавычки, после
|
||||||
|
# неё может идти код («|ГДЕ …"; Х = Модуль.Метод();»).
|
||||||
|
$l = [regex]::Replace($line, '^\s*\|(?:[^"]|"")*("|$)', '""')
|
||||||
|
# Литерал до закрывающей кавычки или, если строка продолжится ниже, до конца строки.
|
||||||
|
$l = [regex]::Replace($l, '"(?:[^"]|"")*("|$)', '""')
|
||||||
|
$ci = $l.IndexOf('//')
|
||||||
|
if ($ci -ge 0) { $l = $l.Substring(0, $ci) }
|
||||||
|
[void]$out.AppendLine($l)
|
||||||
|
}
|
||||||
|
return $out.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
$commonModuleFlags = @('Global', 'ClientManagedApplication', 'Server', 'ExternalConnection', 'ClientOrdinaryApplication', 'ServerCall', 'Privileged')
|
||||||
|
$commonModules = [ordered]@{} # имя из выгрузки -> @{ флаг = 'true'|'false' }
|
||||||
|
if ($ConfigSrc) {
|
||||||
|
$cmDir = Join-Path $ConfigSrc "CommonModules"
|
||||||
|
if (-not (Test-Path -LiteralPath $cmDir -PathType Container)) {
|
||||||
|
Write-Host "WARNING: в -ConfigSrc нет каталога CommonModules: $ConfigSrc" -ForegroundColor Yellow
|
||||||
|
} else {
|
||||||
|
# Идентификаторы 1С регистронезависимы — и имена модулей в коде тоже.
|
||||||
|
$known = New-Object 'System.Collections.Generic.Dictionary[string,string]' ([StringComparer]::OrdinalIgnoreCase)
|
||||||
|
foreach ($f in (Get-ChildItem -LiteralPath $cmDir -Filter "*.xml" -File)) { $known[$f.BaseName] = $f.FullName }
|
||||||
|
$used = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase)
|
||||||
|
foreach ($f in (Get-ChildItem -LiteralPath $SourceDir -Filter "*.bsl" -Recurse -File)) {
|
||||||
|
$code = Remove-BslNoise ([System.IO.File]::ReadAllText($f.FullName, [System.Text.Encoding]::UTF8))
|
||||||
|
foreach ($m in [regex]::Matches($code, '(?<![\w.])([^\W\d]\w*)\s*\.')) { [void]$used.Add($m.Groups[1].Value) }
|
||||||
|
}
|
||||||
|
$names = @($used | Where-Object { $known.ContainsKey($_) } | ForEach-Object { [IO.Path]::GetFileNameWithoutExtension($known[$_]) })
|
||||||
|
[Array]::Sort($names, [StringComparer]::Ordinal)
|
||||||
|
foreach ($n in $names) {
|
||||||
|
$t = [System.IO.File]::ReadAllText($known[$n], [System.Text.Encoding]::UTF8)
|
||||||
|
$flags = @{}
|
||||||
|
foreach ($fl in $commonModuleFlags) {
|
||||||
|
$flags[$fl] = if ($t -match "<$fl>(true|false)</$fl>") { $Matches[1].ToLower() } else { 'false' }
|
||||||
|
}
|
||||||
|
$commonModules[$n] = $flags
|
||||||
|
}
|
||||||
|
if ($commonModules.Count -gt 0) {
|
||||||
|
Write-Host "Общие модули из configSrc: $(@($commonModules.Keys) -join ', ')"
|
||||||
|
} else {
|
||||||
|
Write-Host "Общие модули из configSrc: не понадобились"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$hasRefTypes = $typeMap.Count -gt 0
|
$hasRefTypes = $typeMap.Count -gt 0
|
||||||
# Конфигурация нужна и тогда, когда ссылочных типов нет: в неё кладётся сам объект.
|
# Конфигурация нужна и тогда, когда ссылочных типов нет: в неё кладётся сам объект.
|
||||||
$embedRequested = -not [string]::IsNullOrWhiteSpace($EmbedSourceFile)
|
$embedRequested = -not [string]::IsNullOrWhiteSpace($EmbedSourceFile)
|
||||||
$needCfg = $hasRefTypes -or $embedRequested
|
$needCfg = $hasRefTypes -or $embedRequested -or $commonModules.Count -gt 0
|
||||||
|
|
||||||
# --- 2. Determine TempBasePath ---
|
# --- 2. Determine TempBasePath ---
|
||||||
if (-not $TempBasePath) {
|
if (-not $TempBasePath) {
|
||||||
@@ -673,6 +735,7 @@ if ($needCfg) {
|
|||||||
|
|
||||||
# ChildObjects entries
|
# ChildObjects entries
|
||||||
$childXml = "`r`n`t`t`t<Language>Русский</Language>"
|
$childXml = "`r`n`t`t`t<Language>Русский</Language>"
|
||||||
|
foreach ($cmName in $commonModules.Keys) { $childXml += "`r`n`t`t`t<CommonModule>$cmName</CommonModule>" }
|
||||||
foreach ($metaType in $typeMap.Keys) {
|
foreach ($metaType in $typeMap.Keys) {
|
||||||
if (-not $metaInfo.ContainsKey($metaType)) { continue }
|
if (-not $metaInfo.ContainsKey($metaType)) { continue }
|
||||||
$tag = $metaInfo[$metaType].tag
|
$tag = $metaInfo[$metaType].tag
|
||||||
@@ -779,6 +842,34 @@ if ($needCfg) {
|
|||||||
"@
|
"@
|
||||||
[System.IO.File]::WriteAllText((Join-Path $langDir "Русский.xml"), $langXml, $enc)
|
[System.IO.File]::WriteAllText((Join-Path $langDir "Русский.xml"), $langXml, $enc)
|
||||||
|
|
||||||
|
# --- 4b'. Common modules: пустые двойники с флагами контекста из выгрузки ---
|
||||||
|
if ($commonModules.Count -gt 0) {
|
||||||
|
$cmOutDir = Join-Path $cfgDir "CommonModules"
|
||||||
|
New-Item -ItemType Directory -Path $cmOutDir -Force | Out-Null
|
||||||
|
foreach ($cmName in $commonModules.Keys) {
|
||||||
|
$flags = $commonModules[$cmName]
|
||||||
|
$flagXml = ""
|
||||||
|
foreach ($fl in $commonModuleFlags) { $flagXml += "`r`n`t`t`t<$fl>$($flags[$fl])</$fl>" }
|
||||||
|
$cmXml = @"
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MetaDataObject $ns>
|
||||||
|
<CommonModule uuid="$([guid]::NewGuid().ToString())">
|
||||||
|
<Properties>
|
||||||
|
<Name>$cmName</Name>
|
||||||
|
<Synonym/>
|
||||||
|
<Comment/>$flagXml
|
||||||
|
<ReturnValuesReuse>DontUse</ReturnValuesReuse>
|
||||||
|
</Properties>
|
||||||
|
</CommonModule>
|
||||||
|
</MetaDataObject>
|
||||||
|
"@
|
||||||
|
[System.IO.File]::WriteAllText((Join-Path $cmOutDir "$cmName.xml"), $cmXml, $enc)
|
||||||
|
$cmExt = Join-Path $cmOutDir (Join-Path $cmName "Ext")
|
||||||
|
New-Item -ItemType Directory -Path $cmExt -Force | Out-Null
|
||||||
|
[System.IO.File]::WriteAllText((Join-Path $cmExt "Module.bsl"), "", $enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# --- 4c. Metadata object stubs ---
|
# --- 4c. Metadata object stubs ---
|
||||||
foreach ($metaType in $typeMap.Keys) {
|
foreach ($metaType in $typeMap.Keys) {
|
||||||
if (-not $metaInfo.ContainsKey($metaType)) { continue }
|
if (-not $metaInfo.ContainsKey($metaType)) { continue }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# stub-db-create v1.11 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
# stub-db-create v1.12 — 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
|
||||||
@@ -1216,6 +1216,100 @@ def add_source_object_to_config(source_xml, cfg_dir):
|
|||||||
return {'tag': cfg_tag, 'name': name}
|
return {'tag': cfg_tag, 'name': name}
|
||||||
|
|
||||||
|
|
||||||
|
# --- Общие модули целевой конфигурации, к которым обращается код ---
|
||||||
|
# Проверка модулей (замер 8.3.24, 8.3.27) требует от общего модуля только двух вещей: чтобы он
|
||||||
|
# существовал и был доступен в контексте вызова. Методы, их экспорт и число параметров она не
|
||||||
|
# сверяет. Поэтому двойнику хватает имени и флагов контекста из настоящей выгрузки, тело пустое,
|
||||||
|
# и зависимости модуля за ним не тянутся. Двойник получает только имя, которое есть в выгрузке:
|
||||||
|
# неизвестное имя остаётся ошибкой проверки, а не угадывается.
|
||||||
|
|
||||||
|
COMMON_MODULE_FLAGS = ['Global', 'ClientManagedApplication', 'Server', 'ExternalConnection',
|
||||||
|
'ClientOrdinaryApplication', 'ServerCall', 'Privileged']
|
||||||
|
|
||||||
|
|
||||||
|
def remove_bsl_noise(code):
|
||||||
|
# Код без строковых литералов и комментариев: слова в них — не обращения к модулям.
|
||||||
|
out = []
|
||||||
|
for line in re.split(r'\r?\n', code):
|
||||||
|
# Продолжение многострочной строки («|ВЫБРАТЬ …»): литерал до закрывающей кавычки, после
|
||||||
|
# неё может идти код («|ГДЕ …"; Х = Модуль.Метод();»).
|
||||||
|
line = re.sub(r'^\s*\|(?:[^"]|"")*("|$)', '""', line)
|
||||||
|
# Литерал до закрывающей кавычки или, если строка продолжится ниже, до конца строки.
|
||||||
|
line = re.sub(r'"(?:[^"]|"")*("|$)', '""', line)
|
||||||
|
ci = line.find('//')
|
||||||
|
if ci >= 0:
|
||||||
|
line = line[:ci]
|
||||||
|
out.append(line)
|
||||||
|
return '\n'.join(out) + '\n'
|
||||||
|
|
||||||
|
|
||||||
|
def scan_common_modules(source_dir, config_src):
|
||||||
|
"""\u0418\u043c\u044f \u0438\u0437 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 -> {\u0444\u043b\u0430\u0433: 'true'|'false'} \u0434\u043b\u044f \u043e\u0431\u0449\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0434."""
|
||||||
|
result = {}
|
||||||
|
if not config_src:
|
||||||
|
return result
|
||||||
|
cm_dir = os.path.join(config_src, 'CommonModules')
|
||||||
|
if not os.path.isdir(cm_dir):
|
||||||
|
print('WARNING: \u0432 -ConfigSrc \u043d\u0435\u0442 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 CommonModules: %s' % config_src)
|
||||||
|
return result
|
||||||
|
# Идентификаторы 1С регистронезависимы — и имена модулей в коде тоже.
|
||||||
|
known = {}
|
||||||
|
for fn in os.listdir(cm_dir):
|
||||||
|
full = os.path.join(cm_dir, fn)
|
||||||
|
if fn.lower().endswith('.xml') and os.path.isfile(full):
|
||||||
|
known[os.path.splitext(fn)[0].casefold()] = full
|
||||||
|
used = set()
|
||||||
|
for root, _dirs, files in os.walk(source_dir):
|
||||||
|
for fn in files:
|
||||||
|
if not fn.lower().endswith('.bsl'):
|
||||||
|
continue
|
||||||
|
# Битые байты (файл не в UTF-8) заменяются, как в PS-мастере, а не валят заглушку.
|
||||||
|
with open(os.path.join(root, fn), 'r', encoding='utf-8-sig', errors='replace') as fh:
|
||||||
|
code = remove_bsl_noise(fh.read())
|
||||||
|
for m in re.finditer(r'(?<![\w.])([^\W\d]\w*)\s*\.', code):
|
||||||
|
used.add(m.group(1).casefold())
|
||||||
|
names = sorted(os.path.splitext(os.path.basename(known[u]))[0] for u in used if u in known)
|
||||||
|
for n in names:
|
||||||
|
with open(known[n.casefold()], 'r', encoding='utf-8-sig') as fh:
|
||||||
|
t = fh.read()
|
||||||
|
flags = {}
|
||||||
|
for fl in COMMON_MODULE_FLAGS:
|
||||||
|
m = re.search(r'<%s>(true|false)</%s>' % (fl, fl), t, re.IGNORECASE)
|
||||||
|
flags[fl] = m.group(1).lower() if m else 'false'
|
||||||
|
result[n] = flags
|
||||||
|
if result:
|
||||||
|
print('\u041e\u0431\u0449\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0438\u0437 configSrc: %s' % ', '.join(result.keys()))
|
||||||
|
else:
|
||||||
|
print('\u041e\u0431\u0449\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0438\u0437 configSrc: \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u0438\u0441\u044c')
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def write_common_module_stubs(cfg_dir, ns_decl, common_modules):
|
||||||
|
# Пустые двойники с флагами контекста из выгрузки.
|
||||||
|
if not common_modules:
|
||||||
|
return
|
||||||
|
cm_out = os.path.join(cfg_dir, 'CommonModules')
|
||||||
|
os.makedirs(cm_out, exist_ok=True)
|
||||||
|
for name, flags in common_modules.items():
|
||||||
|
flag_xml = ''.join('\n\t\t\t<%s>%s</%s>' % (fl, flags[fl], fl) for fl in COMMON_MODULE_FLAGS)
|
||||||
|
cm_xml = f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MetaDataObject {ns_decl}>
|
||||||
|
\t<CommonModule uuid="{new_uuid()}">
|
||||||
|
\t\t<Properties>
|
||||||
|
\t\t\t<Name>{name}</Name>
|
||||||
|
\t\t\t<Synonym/>
|
||||||
|
\t\t\t<Comment/>{flag_xml}
|
||||||
|
\t\t\t<ReturnValuesReuse>DontUse</ReturnValuesReuse>
|
||||||
|
\t\t</Properties>
|
||||||
|
\t</CommonModule>
|
||||||
|
</MetaDataObject>
|
||||||
|
"""
|
||||||
|
write_bom(os.path.join(cm_out, name + '.xml'), cm_xml)
|
||||||
|
ext_dir = os.path.join(cm_out, name, 'Ext')
|
||||||
|
os.makedirs(ext_dir, exist_ok=True)
|
||||||
|
write_bom(os.path.join(ext_dir, 'Module.bsl'), '')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding='utf-8')
|
sys.stdout.reconfigure(encoding='utf-8')
|
||||||
sys.stderr.reconfigure(encoding='utf-8')
|
sys.stderr.reconfigure(encoding='utf-8')
|
||||||
@@ -1227,6 +1321,9 @@ def main():
|
|||||||
# XML проверяемой обработки/отчёта: объект кладётся в конфигурацию-заглушку, чтобы платформа
|
# XML проверяемой обработки/отчёта: объект кладётся в конфигурацию-заглушку, чтобы платформа
|
||||||
# смогла проверить его штатными проверками. Без параметра стаб работает как раньше.
|
# смогла проверить его штатными проверками. Без параметра стаб работает как раньше.
|
||||||
parser.add_argument('-EmbedSourceFile', default='')
|
parser.add_argument('-EmbedSourceFile', default='')
|
||||||
|
# Выгрузка целевой конфигурации: общие модули, к которым обращается код, получают в заглушке
|
||||||
|
# пустых двойников с настоящими флагами контекста.
|
||||||
|
parser.add_argument('-ConfigSrc', default='')
|
||||||
parser.add_argument('-AdditionalV8Arguments', nargs='*', default=[],
|
parser.add_argument('-AdditionalV8Arguments', nargs='*', default=[],
|
||||||
help='Extra 1cv8 arguments, e.g. /UseHwLicenses+')
|
help='Extra 1cv8 arguments, e.g. /UseHwLicenses+')
|
||||||
parser.add_argument('-AdditionalIbcmdArguments', nargs='*', default=[],
|
parser.add_argument('-AdditionalIbcmdArguments', nargs='*', default=[],
|
||||||
@@ -1239,12 +1336,14 @@ def main():
|
|||||||
args.V8Path = clean_path(args.V8Path, "-V8Path")
|
args.V8Path = clean_path(args.V8Path, "-V8Path")
|
||||||
args.TempBasePath = clean_path(args.TempBasePath, "-TempBasePath")
|
args.TempBasePath = clean_path(args.TempBasePath, "-TempBasePath")
|
||||||
args.EmbedSourceFile = clean_path(args.EmbedSourceFile, "-EmbedSourceFile")
|
args.EmbedSourceFile = clean_path(args.EmbedSourceFile, "-EmbedSourceFile")
|
||||||
|
args.ConfigSrc = clean_path(args.ConfigSrc, "-ConfigSrc")
|
||||||
|
|
||||||
type_map = scan_ref_types(args.SourceDir)
|
type_map = scan_ref_types(args.SourceDir)
|
||||||
register_columns = scan_register_columns(args.SourceDir)
|
register_columns = scan_register_columns(args.SourceDir)
|
||||||
|
common_modules = scan_common_modules(args.SourceDir, args.ConfigSrc)
|
||||||
has_ref_types = len(type_map) > 0
|
has_ref_types = len(type_map) > 0
|
||||||
embed_requested = bool(args.EmbedSourceFile and args.EmbedSourceFile.strip())
|
embed_requested = bool(args.EmbedSourceFile and args.EmbedSourceFile.strip())
|
||||||
need_cfg = has_ref_types or embed_requested
|
need_cfg = has_ref_types or embed_requested or len(common_modules) > 0
|
||||||
stub_format_version = detect_stub_format_version(args.SourceDir)
|
stub_format_version = detect_stub_format_version(args.SourceDir)
|
||||||
stub_compat = stub_compatibility_mode(stub_format_version)
|
stub_compat = stub_compatibility_mode(stub_format_version)
|
||||||
ns_decl = f'{NS} version="{stub_format_version}"'
|
ns_decl = f'{NS} version="{stub_format_version}"'
|
||||||
@@ -1279,6 +1378,8 @@ def main():
|
|||||||
co_xml += f'\n\t\t\t<xr:ContainedObject>\n\t\t\t\t<xr:ClassId>{CLASS_IDS[i]}</xr:ClassId>\n\t\t\t\t<xr:ObjectId>{co_ids[i]}</xr:ObjectId>\n\t\t\t</xr:ContainedObject>'
|
co_xml += f'\n\t\t\t<xr:ContainedObject>\n\t\t\t\t<xr:ClassId>{CLASS_IDS[i]}</xr:ClassId>\n\t\t\t\t<xr:ObjectId>{co_ids[i]}</xr:ObjectId>\n\t\t\t</xr:ContainedObject>'
|
||||||
|
|
||||||
child_xml = '\n\t\t\t<Language>\u0420\u0443\u0441\u0441\u043a\u0438\u0439</Language>' # Русский
|
child_xml = '\n\t\t\t<Language>\u0420\u0443\u0441\u0441\u043a\u0438\u0439</Language>' # Русский
|
||||||
|
for cm_name in common_modules:
|
||||||
|
child_xml += '\n\t\t\t<CommonModule>%s</CommonModule>' % cm_name
|
||||||
for meta_type, names in type_map.items():
|
for meta_type, names in type_map.items():
|
||||||
if meta_type not in META_INFO:
|
if meta_type not in META_INFO:
|
||||||
continue
|
continue
|
||||||
@@ -1381,6 +1482,8 @@ def main():
|
|||||||
"""
|
"""
|
||||||
write_bom(os.path.join(lang_dir, '\u0420\u0443\u0441\u0441\u043a\u0438\u0439.xml'), lang_xml)
|
write_bom(os.path.join(lang_dir, '\u0420\u0443\u0441\u0441\u043a\u0438\u0439.xml'), lang_xml)
|
||||||
|
|
||||||
|
write_common_module_stubs(cfg_dir, ns_decl, common_modules)
|
||||||
|
|
||||||
# Metadata stubs
|
# Metadata stubs
|
||||||
for meta_type, names in type_map.items():
|
for meta_type, names in type_map.items():
|
||||||
if meta_type not in META_INFO:
|
if meta_type not in META_INFO:
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-bu
|
|||||||
| `-OutputFile <путь>` | да | Путь к выходному ERF-файлу |
|
| `-OutputFile <путь>` | да | Путь к выходному ERF-файлу |
|
||||||
| `-Checks <список>` | нет | Что проверить перед сборкой: `modules`, `handlers`, `unreferenced`, `empty-handlers`, `config`; `off` — не проверять. По умолчанию `modules,handlers` |
|
| `-Checks <список>` | нет | Что проверить перед сборкой: `modules`, `handlers`, `unreferenced`, `empty-handlers`, `config`; `off` — не проверять. По умолчанию `modules,handlers` |
|
||||||
| `-Context <список>` | нет | Контексты проверки `modules`: `ThinClient`, `Server`, `ExternalConnection`, `ThickClientOrdinaryApplication`. По умолчанию `ThinClient,Server` |
|
| `-Context <список>` | нет | Контексты проверки `modules`: `ThinClient`, `Server`, `ExternalConnection`, `ThickClientOrdinaryApplication`. По умолчанию `ThinClient,Server` |
|
||||||
|
| `-ConfigSrc <путь>` | нет | Каталог XML-выгрузки конфигурации, в которой будет работать отчёт. По умолчанию — `configSrc` указанной базы из `.v8-project.json` |
|
||||||
| `-AdditionalV8Arguments <список>` | нет | Доп. аргументы запуска `1cv8.exe` через запятую, напр. `/UseHwLicenses+` |
|
| `-AdditionalV8Arguments <список>` | нет | Доп. аргументы запуска `1cv8.exe` через запятую, напр. `/UseHwLicenses+` |
|
||||||
| `-AdditionalIbcmdArguments <список>` | нет | Доп. аргументы `ibcmd` через запятую, в форме `--ключ=значение` |
|
| `-AdditionalIbcmdArguments <список>` | нет | Доп. аргументы `ibcmd` через запятую, в форме `--ключ=значение` |
|
||||||
|
|
||||||
@@ -74,6 +75,12 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-bu
|
|||||||
|
|
||||||
Проверка идёт на отдельной временной базе, даже если база указана: чужую конфигурацию навык не трогает.
|
Проверка идёт на отдельной временной базе, даже если база указана: чужую конфигурацию навык не трогает.
|
||||||
|
|
||||||
|
Общие модули конфигурации (`ОбщегоНазначения`, `УправлениеПечатью` и т.п.) проверка видит только
|
||||||
|
при известной выгрузке конфигурации — `-ConfigSrc` или `configSrc` базы в `.v8-project.json`.
|
||||||
|
Без неё обращения к ним — ошибка «Переменная не определена»; тогда укажи выгрузку или собери
|
||||||
|
с `-Checks off`. Методы глобальных общих модулей, вызванные без имени модуля, проверка не видит
|
||||||
|
и с выгрузкой — для такого кода остаётся `-Checks off`.
|
||||||
|
|
||||||
## Примеры
|
## Примеры
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"name": "С -ConfigSrc: модуль есть, но не в контексте / модуля нет — разные подсказки, без -Checks off (fake platform)",
|
||||||
|
"osOnly": "win32",
|
||||||
|
"fakePlatform": {
|
||||||
|
"exit": 0,
|
||||||
|
"log": "",
|
||||||
|
"check": {
|
||||||
|
"exit": 101,
|
||||||
|
"log": "{Обработка.Тест.МодульОбъекта(2,2)}: Переменная не определена (ОбщегоНазначения)\r\n\t<<?>>ОбщегоНазначения.СообщитьПользователю(\"x\"); (Проверка: Сервер)\r\n{Обработка.Тест.МодульОбъекта(3,2)}: Переменная не определена (ОбщегоНазначениеее)\r\n\t<<?>>ОбщегоНазначениеее.Метод(); (Проверка: Сервер)\r\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preRun": [
|
||||||
|
{
|
||||||
|
"script": "epf-init/scripts/init",
|
||||||
|
"args": {
|
||||||
|
"-Name": "Тест",
|
||||||
|
"-SrcDir": "{workDir}/src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "src/Тест/Ext/ObjectModule.bsl",
|
||||||
|
"content": "Процедура Проба()\r\n\tОбщегоНазначения.СообщитьПользователю(\"x\");\r\nКонецПроцедуры\r\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/ОбщегоНазначения.xml",
|
||||||
|
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.17\">\n\t<CommonModule uuid=\"10000000-0000-0000-0000-000000000001\">\n\t\t<Properties>\n\t\t\t<Name>ОбщегоНазначения</Name>\n\t\t\t<Server>true</Server>\n\t\t</Properties>\n\t</CommonModule>\n</MetaDataObject>\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args_extra": [
|
||||||
|
"-V8Path",
|
||||||
|
"{workDir}\\fake.cmd",
|
||||||
|
"-InfoBasePath",
|
||||||
|
"{workDir}\\ib",
|
||||||
|
"-SourceFile",
|
||||||
|
"{workDir}\\src\\Тест.xml",
|
||||||
|
"-OutputFile",
|
||||||
|
"{workDir}\\build\\Тест.epf",
|
||||||
|
"-ConfigSrc",
|
||||||
|
"{workDir}\\cfgsrc"
|
||||||
|
],
|
||||||
|
"expect": {
|
||||||
|
"stdoutContains": [
|
||||||
|
"Общие модули из configSrc: ОбщегоНазначения",
|
||||||
|
"[hint] общий модуль ОбщегоНазначения есть в configSrc, но недоступен в контексте проверки",
|
||||||
|
"[hint] общего модуля ОбщегоНазначениеее нет в configSrc"
|
||||||
|
],
|
||||||
|
"stdoutNotContains": [
|
||||||
|
"/LoadExternalDataProcessorOrReportFromFiles",
|
||||||
|
"-Checks off"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expectError": true,
|
||||||
|
"noSnapshot": "сборка отменена — артефакта нет по замыслу"
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "Неопределённый общий модуль без configSrc: подсказка про -ConfigSrc и -Checks off (fake platform)",
|
||||||
|
"osOnly": "win32",
|
||||||
|
"fakePlatform": {
|
||||||
|
"exit": 0,
|
||||||
|
"log": "",
|
||||||
|
"check": {
|
||||||
|
"exit": 101,
|
||||||
|
"log": "{Обработка.Тест.МодульОбъекта(2,2)}: Переменная не определена (ОбщегоНазначения)\r\n\t<<?>>ОбщегоНазначения.СообщитьПользователю(\"x\"); (Проверка: Сервер)\r\n{Обработка.Тест.МодульОбъекта(3,2)}: Переменная не определена (ОбщегоНазначения)\r\n\t<<?>>ОбщегоНазначения.Прочее(); (Проверка: Сервер)\r\n{Обработка.Тест.МодульОбъекта(4,2)}: Переменная не определена (Сумма)\r\n\tХ = <<?>>Сумма + 1; (Проверка: Сервер)\r\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preRun": [
|
||||||
|
{
|
||||||
|
"script": "epf-init/scripts/init",
|
||||||
|
"args": {
|
||||||
|
"-Name": "Тест",
|
||||||
|
"-SrcDir": "{workDir}/src"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args_extra": [
|
||||||
|
"-V8Path",
|
||||||
|
"{workDir}\\fake.cmd",
|
||||||
|
"-InfoBasePath",
|
||||||
|
"{workDir}\\ib",
|
||||||
|
"-SourceFile",
|
||||||
|
"{workDir}\\src\\Тест.xml",
|
||||||
|
"-OutputFile",
|
||||||
|
"{workDir}\\build\\Тест.epf"
|
||||||
|
],
|
||||||
|
"expect": {
|
||||||
|
"stdoutContains": [
|
||||||
|
"[hint] похоже на общий модуль конфигурации",
|
||||||
|
"[hint] Общие модули конфигурации проверке не видны: ОбщегоНазначения.",
|
||||||
|
"-Checks off"
|
||||||
|
],
|
||||||
|
"stdoutNotContains": [
|
||||||
|
"/LoadExternalDataProcessorOrReportFromFiles",
|
||||||
|
"проверке не видны: ОбщегоНазначения, Сумма"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expectError": true,
|
||||||
|
"noSnapshot": "сборка отменена — артефакта нет по замыслу"
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
{
|
||||||
|
"name": "Общие модули из -ConfigSrc: только те, к которым обращается код, с флагами из выгрузки",
|
||||||
|
"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</Properties>\n\t\t<ChildObjects/>\n\t</ExternalDataProcessor>\n</MetaDataObject>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "src/Проба/Ext/ObjectModule.bsl",
|
||||||
|
"content": "Процедура Проба()\r\n\tОбщМод.Метод();\r\n\tобщмод2.Метод(\"ЛишнийМодуль.Х\"); // КомментМодуль.Х\r\n\tТекст = \"ВЫБРАТЬ\r\n\t|ТекстМодуль.Поле\";\r\n\tНетВКонфиге.Метод();\r\n\tЗапрос.Текст = Модуль3 .Поле;\r\nТ = \"ВЫБРАТЬ\r\n\t|ГДЕ Ложь\"; Модуль4.Метод();\r\nКонецПроцедуры\r\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/ОбщМод.xml",
|
||||||
|
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.20\">\n\t<CommonModule uuid=\"10000000-0000-0000-0000-000000000001\">\n\t\t<Properties>\n\t\t\t<Name>ОбщМод</Name>\n\t\t\t<Global>false</Global>\n\t\t\t<ClientManagedApplication>false</ClientManagedApplication>\n\t\t\t<Server>true</Server>\n\t\t\t<ExternalConnection>true</ExternalConnection>\n\t\t\t<ClientOrdinaryApplication>false</ClientOrdinaryApplication>\n\t\t\t<ServerCall>true</ServerCall>\n\t\t\t<Privileged>false</Privileged>\n\t\t\t<ReturnValuesReuse>DuringRequest</ReturnValuesReuse>\n\t\t</Properties>\n\t</CommonModule>\n</MetaDataObject>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/ОбщМод2.xml",
|
||||||
|
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.20\">\n\t<CommonModule uuid=\"10000000-0000-0000-0000-000000000002\">\n\t\t<Properties>\n\t\t\t<Name>ОбщМод2</Name>\n\t\t\t<ClientManagedApplication>true</ClientManagedApplication>\n\t\t\t<Server>true</Server>\n\t\t</Properties>\n\t</CommonModule>\n</MetaDataObject>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/Модуль3.xml",
|
||||||
|
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.20\">\n\t<CommonModule uuid=\"10000000-0000-0000-0000-000000000003\">\n\t\t<Properties>\n\t\t\t<Name>Модуль3</Name>\n\t\t\t<Server>true</Server>\n\t\t</Properties>\n\t</CommonModule>\n</MetaDataObject>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/ЛишнийМодуль.xml",
|
||||||
|
"content": "<MetaDataObject/>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/КомментМодуль.xml",
|
||||||
|
"content": "<MetaDataObject/>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/ТекстМодуль.xml",
|
||||||
|
"content": "<MetaDataObject/>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/НеИспользуется.xml",
|
||||||
|
"content": "<MetaDataObject/>\n"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"writeFile": {
|
||||||
|
"path": "cfgsrc/CommonModules/Модуль4.xml",
|
||||||
|
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject xmlns=\"http://v8.1c.ru/8.3/MDClasses\" version=\"2.20\">\n\t<CommonModule uuid=\"10000000-0000-0000-0000-000000000004\">\n\t\t<Properties>\n\t\t\t<Name>Модуль4</Name>\n\t\t\t<Server>true</Server>\n\t\t</Properties>\n\t</CommonModule>\n</MetaDataObject>\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args_extra": [
|
||||||
|
"-SourceDir",
|
||||||
|
"{workDir}/src",
|
||||||
|
"-V8Path",
|
||||||
|
"{fakePlatform}",
|
||||||
|
"-TempBasePath",
|
||||||
|
"{workDir}/base",
|
||||||
|
"-EmbedSourceFile",
|
||||||
|
"{workDir}/src/Проба.xml",
|
||||||
|
"-ConfigSrc",
|
||||||
|
"{workDir}/cfgsrc"
|
||||||
|
],
|
||||||
|
"expect": {
|
||||||
|
"stdoutContains": [
|
||||||
|
"Общие модули из configSrc: Модуль3, Модуль4, ОбщМод, ОбщМод2"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"base/cfg/CommonModules/ОбщМод/Ext/Module.bsl",
|
||||||
|
"base/cfg/CommonModules/ОбщМод2/Ext/Module.bsl",
|
||||||
|
"base/cfg/CommonModules/Модуль3.xml"
|
||||||
|
],
|
||||||
|
"filesAbsent": [
|
||||||
|
"base/cfg/CommonModules/ЛишнийМодуль.xml",
|
||||||
|
"base/cfg/CommonModules/КомментМодуль.xml",
|
||||||
|
"base/cfg/CommonModules/ТекстМодуль.xml",
|
||||||
|
"base/cfg/CommonModules/НеИспользуется.xml",
|
||||||
|
"base/cfg/CommonModules/НетВКонфиге.xml"
|
||||||
|
],
|
||||||
|
"fileContains": [
|
||||||
|
{
|
||||||
|
"file": "base/cfg/CommonModules/ОбщМод.xml",
|
||||||
|
"text": [
|
||||||
|
"<Name>ОбщМод</Name>",
|
||||||
|
"<ClientManagedApplication>false</ClientManagedApplication>",
|
||||||
|
"<Server>true</Server>",
|
||||||
|
"<ExternalConnection>true</ExternalConnection>",
|
||||||
|
"<ServerCall>true</ServerCall>",
|
||||||
|
"version=\"2.17\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/CommonModules/ОбщМод2.xml",
|
||||||
|
"text": [
|
||||||
|
"<Name>ОбщМод2</Name>",
|
||||||
|
"<ClientManagedApplication>true</ClientManagedApplication>",
|
||||||
|
"<ServerCall>false</ServerCall>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/Configuration.xml",
|
||||||
|
"text": [
|
||||||
|
"<CommonModule>ОбщМод</CommonModule>",
|
||||||
|
"<CommonModule>ОбщМод2</CommonModule>",
|
||||||
|
"<CommonModule>Модуль3</CommonModule>"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expectError": true,
|
||||||
|
"noSnapshot": "платформа фейковая: проверяется сгенерированная конфигурация, а не база"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user