mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-29 05:25:53 +03:00
feat(subsystem-validate): проверка 14 — тела Ext/*.xml в версии дескриптора; сверка с выгрузкой
Дескриптор подсистемы и её штампованные тела (CommandInterface.xml, Help.xml) платформа загружает только в одной версии формата («Версия формата загружаемого файла … отличается от версии формата ранее загруженных файлов»), проверено на 8.3.27.1859. Расхождение — ошибка. Вложенные подсистемы — отдельные объекты и сюда не входят. Подсистема целиком в другой версии, чем выгрузка, грузится — это лишь неоднородность выгрузки, поэтому такое расхождение только предупреждение. Co-Authored-By: Sergei Pleshanov <2357qwr@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Sergei Pleshanov
Claude Opus 5.5
parent
bcbc79c415
commit
6978318fa1
@@ -1,4 +1,4 @@
|
||||
# subsystem-validate v1.5 — Validate 1C subsystem XML structure
|
||||
# subsystem-validate v1.6 — Validate 1C subsystem XML structure
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
[CmdletBinding(PositionalBinding=$false)]
|
||||
param(
|
||||
@@ -11,6 +11,49 @@ param(
|
||||
$ErrorActionPreference = "Stop"
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# Штамп версии формата — атрибут version КОРНЕВОГО элемента файла. Копия общего эталона (семья
|
||||
# root_version, авторитет — meta-validate).
|
||||
function Get-RootVersion([string]$xmlPath) {
|
||||
if (-not (Test-Path -LiteralPath $xmlPath -PathType Leaf)) { return $null }
|
||||
$buf = New-Object byte[] 4096
|
||||
$fs = [System.IO.File]::OpenRead($xmlPath)
|
||||
try { $len = $fs.Read($buf, 0, $buf.Length) } finally { $fs.Dispose() }
|
||||
$head = [System.Text.Encoding]::UTF8.GetString($buf, 0, $len)
|
||||
$m = [regex]::Match($head, '<[A-Za-z_][\w.:-]*(\s[^>]*)?/?>')
|
||||
if (-not $m.Success) { return $null }
|
||||
$v = [regex]::Match($m.Groups[1].Value, '(?:^|\s)version="([^"]*)"')
|
||||
if ($v.Success) { return $v.Groups[1].Value }
|
||||
return $null
|
||||
}
|
||||
|
||||
# Корень автономной внешней обработки/отчёта. Копия общего эталона (семья is_external_root,
|
||||
# авторитет — cf-edit).
|
||||
function Test-ExternalObjectRoot([string]$xmlPath) {
|
||||
if (-not (Test-Path $xmlPath)) { return $false }
|
||||
try {
|
||||
[xml]$mx = Get-Content -Path $xmlPath -Encoding UTF8
|
||||
$el = $mx.DocumentElement.FirstChild
|
||||
while ($el -and $el.NodeType -ne 'Element') { $el = $el.NextSibling }
|
||||
if ($el) { return @('ExternalDataProcessor','ExternalReport') -contains $el.LocalName }
|
||||
} catch {}
|
||||
return $false
|
||||
}
|
||||
|
||||
# Якорь выгрузки: корень автономной EPF/ERF либо Configuration.xml, ближайший вверх. Копия общего
|
||||
# эталона (семья find_dump_anchor, авторитет — meta-validate).
|
||||
function Find-DumpAnchor([string]$startDir) {
|
||||
$d = $startDir
|
||||
for ($i = 0; $i -lt 15 -and $d; $i++) {
|
||||
if (Test-ExternalObjectRoot "$d.xml") { return "$d.xml" }
|
||||
$cfg = Join-Path $d "Configuration.xml"
|
||||
if (Test-Path $cfg) { return $cfg }
|
||||
$parent = [System.IO.Path]::GetDirectoryName($d)
|
||||
if (-not $parent -or $parent -eq $d) { break }
|
||||
$d = $parent
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
# --- Resolve path ---
|
||||
if (-not [System.IO.Path]::IsPathRooted($SubsystemPath)) {
|
||||
$SubsystemPath = Join-Path (Get-Location).Path $SubsystemPath
|
||||
@@ -331,6 +374,36 @@ if (-not $script:stopped) {
|
||||
} else {
|
||||
Report-OK "13. UseOneCommand: false (no constraint)"
|
||||
}
|
||||
|
||||
# --- 14. Format version: тела Ext/*.xml — как у дескриптора; сверка с выгрузкой ---
|
||||
# Дескриптор подсистемы и её штампованные тела (CommandInterface.xml, Help.xml) платформа загружает
|
||||
# только в одной версии формата: «Версия формата загружаемого файла … отличается от версии формата
|
||||
# ранее загруженных файлов». Вложенные подсистемы — отдельные объекты. С остальной выгрузкой
|
||||
# подсистема может расходиться — платформа такое грузит, это лишь неоднородность выгрузки (типично
|
||||
# после мержа веток, выгруженных разными платформами).
|
||||
if ($version) {
|
||||
$subExtDir = Join-Path (Join-Path $parentDir2 $baseName2) "Ext"
|
||||
$verBodiesOk = 0
|
||||
$verErrors = 0
|
||||
if (Test-Path $subExtDir -PathType Container) {
|
||||
$bodyNames = @(Get-ChildItem $subExtDir -Filter "*.xml" -File | ForEach-Object { $_.Name })
|
||||
[Array]::Sort($bodyNames, [StringComparer]::Ordinal)
|
||||
foreach ($bn in $bodyNames) {
|
||||
$bodyVer = Get-RootVersion (Join-Path $subExtDir $bn)
|
||||
if (-not $bodyVer) { continue }
|
||||
if ($bodyVer -eq $version) { $verBodiesOk++; continue }
|
||||
$verErrors++
|
||||
Report-Error "14. Format version: $baseName2/Ext/$bn is stamped $bodyVer, the descriptor $version — the platform refuses to load parts of one object in different formats"
|
||||
}
|
||||
}
|
||||
$dumpAnchor = Find-DumpAnchor $parentDir2
|
||||
$dumpVer = if ($dumpAnchor) { Get-RootVersion $dumpAnchor } else { $null }
|
||||
if ($dumpVer -and $version -ne $dumpVer) {
|
||||
Report-Warn "14. Format version $version differs from the dump ($dumpVer) — the platform loads it, but the dump is no longer uniform (typical after merging branches dumped by different platforms)"
|
||||
} elseif ($verErrors -eq 0 -and ($verBodiesOk -gt 0 -or $dumpVer)) {
|
||||
Report-OK "14. Format version: $version, matches the stamped parts and the dump"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Finalize ---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# subsystem-validate v1.5 — Validate 1C subsystem XML structure
|
||||
# subsystem-validate v1.6 — Validate 1C subsystem XML structure
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
"""Validates subsystem XML file structure, properties, content items, child objects."""
|
||||
import sys, os, argparse, re
|
||||
@@ -98,6 +98,56 @@ def find_duplicates(items):
|
||||
return dupes
|
||||
|
||||
|
||||
# Штамп версии формата — атрибут version КОРНЕВОГО элемента файла. Копия общего эталона (семья
|
||||
# root_version, авторитет — meta-validate).
|
||||
def root_version(xml_path):
|
||||
if not os.path.isfile(xml_path):
|
||||
return None
|
||||
with open(xml_path, "rb") as f:
|
||||
head = f.read(4096).decode("utf-8", errors="ignore")
|
||||
m = re.search(r'<[A-Za-z_][\w.:-]*(\s[^>]*)?/?>', head)
|
||||
if not m:
|
||||
return None
|
||||
v = re.search(r'(?:^|\s)version="([^"]*)"', m.group(1) or "")
|
||||
if v:
|
||||
return v.group(1)
|
||||
return None
|
||||
|
||||
|
||||
# Корень автономной внешней обработки/отчёта. Копия общего эталона (семья is_external_root,
|
||||
# авторитет — cf-edit).
|
||||
def _sg_is_external_root(xml_path):
|
||||
if not os.path.isfile(xml_path):
|
||||
return False
|
||||
try:
|
||||
mx = etree.parse(xml_path).getroot()
|
||||
for child in mx:
|
||||
if isinstance(child.tag, str):
|
||||
return child.tag.split("}")[-1] in ("ExternalDataProcessor", "ExternalReport")
|
||||
except Exception:
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
# Якорь выгрузки: корень автономной EPF/ERF либо Configuration.xml, ближайший вверх. Копия общего
|
||||
# эталона (семья find_dump_anchor, авторитет — meta-validate).
|
||||
def find_dump_anchor(start_dir):
|
||||
d = start_dir
|
||||
for _ in range(15):
|
||||
if not d:
|
||||
break
|
||||
if _sg_is_external_root(d + ".xml"):
|
||||
return d + ".xml"
|
||||
cfg = os.path.join(d, "Configuration.xml")
|
||||
if os.path.exists(cfg):
|
||||
return cfg
|
||||
parent = os.path.dirname(d)
|
||||
if not parent or parent == d:
|
||||
break
|
||||
d = parent
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
sys.stderr.reconfigure(encoding="utf-8")
|
||||
@@ -368,6 +418,37 @@ def main():
|
||||
else:
|
||||
r.ok('13. UseOneCommand: false (no constraint)')
|
||||
|
||||
# --- 14. Format version: тела Ext/*.xml — как у дескриптора; сверка с выгрузкой ---
|
||||
# Дескриптор подсистемы и её штампованные тела (CommandInterface.xml, Help.xml) платформа загружает
|
||||
# только в одной версии формата: «Версия формата загружаемого файла … отличается от версии формата
|
||||
# ранее загруженных файлов». Вложенные подсистемы — отдельные объекты. С остальной выгрузкой
|
||||
# подсистема может расходиться — платформа такое грузит, это лишь неоднородность выгрузки (типично
|
||||
# после мержа веток, выгруженных разными платформами).
|
||||
if version:
|
||||
sub_ext_dir = os.path.join(parent_dir2, base_name2, 'Ext')
|
||||
ver_bodies_ok = 0
|
||||
ver_errors = 0
|
||||
if os.path.isdir(sub_ext_dir):
|
||||
body_names = sorted(n for n in os.listdir(sub_ext_dir)
|
||||
if n.lower().endswith('.xml') and os.path.isfile(os.path.join(sub_ext_dir, n)))
|
||||
for bn in body_names:
|
||||
body_ver = root_version(os.path.join(sub_ext_dir, bn))
|
||||
if not body_ver:
|
||||
continue
|
||||
if body_ver == version:
|
||||
ver_bodies_ok += 1
|
||||
continue
|
||||
ver_errors += 1
|
||||
r.error(f'14. Format version: {base_name2}/Ext/{bn} is stamped {body_ver}, the descriptor {version} '
|
||||
'— the platform refuses to load parts of one object in different formats')
|
||||
dump_anchor = find_dump_anchor(parent_dir2)
|
||||
dump_ver = root_version(dump_anchor) if dump_anchor else None
|
||||
if dump_ver and version != dump_ver:
|
||||
r.warn(f'14. Format version {version} differs from the dump ({dump_ver}) — the platform loads it, '
|
||||
'but the dump is no longer uniform (typical after merging branches dumped by different platforms)')
|
||||
elif ver_errors == 0 and (ver_bodies_ok > 0 or dump_ver):
|
||||
r.ok(f'14. Format version: {version}, matches the stamped parts and the dump')
|
||||
|
||||
# --- Finalize ---
|
||||
checks = r.ok_count + r.errors + r.warnings
|
||||
if r.errors == 0 and r.warnings == 0 and not detailed:
|
||||
|
||||
Reference in New Issue
Block a user