mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-13 01:14:56 +03:00
Auto-build: copilot (python) from 7fa279c
This commit is contained in:
@@ -0,0 +1,579 @@
|
||||
# cf-info v1.2 — Compact summary of 1C configuration root
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][Alias('Path')][string]$ConfigPath,
|
||||
[ValidateSet("overview","brief","full")]
|
||||
[string]$Mode = "overview",
|
||||
[Alias('Name')]
|
||||
[ValidateSet("home-page")]
|
||||
[string]$Section,
|
||||
[int]$Limit = 150,
|
||||
[int]$Offset = 0,
|
||||
[string]$OutFile
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# --- Output helper (always collect, paginate at the end) ---
|
||||
$script:lines = @()
|
||||
function Out([string]$text) { $script:lines += $text }
|
||||
|
||||
# --- Resolve path ---
|
||||
if (-not [System.IO.Path]::IsPathRooted($ConfigPath)) {
|
||||
$ConfigPath = Join-Path (Get-Location).Path $ConfigPath
|
||||
}
|
||||
|
||||
# Directory -> find Configuration.xml
|
||||
if (Test-Path $ConfigPath -PathType Container) {
|
||||
$candidate = Join-Path $ConfigPath "Configuration.xml"
|
||||
if (Test-Path $candidate) {
|
||||
$ConfigPath = $candidate
|
||||
} else {
|
||||
Write-Host "[ERROR] No Configuration.xml found in directory: $ConfigPath"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-Path $ConfigPath)) {
|
||||
Write-Host "[ERROR] File not found: $ConfigPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Load XML ---
|
||||
[xml]$xmlDoc = Get-Content -Path $ConfigPath -Encoding UTF8
|
||||
$ns = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable)
|
||||
$ns.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses")
|
||||
$ns.AddNamespace("v8", "http://v8.1c.ru/8.1/data/core")
|
||||
$ns.AddNamespace("xr", "http://v8.1c.ru/8.3/xcf/readable")
|
||||
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
$ns.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema")
|
||||
$ns.AddNamespace("app", "http://v8.1c.ru/8.2/managed-application/core")
|
||||
|
||||
$mdRoot = $xmlDoc.SelectSingleNode("/md:MetaDataObject", $ns)
|
||||
if (-not $mdRoot) {
|
||||
Write-Host "[ERROR] Not a valid 1C metadata XML file (no MetaDataObject root)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$cfgNode = $mdRoot.SelectSingleNode("md:Configuration", $ns)
|
||||
if (-not $cfgNode) {
|
||||
Write-Host "[ERROR] No <Configuration> element found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$version = $mdRoot.GetAttribute("version")
|
||||
$propsNode = $cfgNode.SelectSingleNode("md:Properties", $ns)
|
||||
$childObjNode = $cfgNode.SelectSingleNode("md:ChildObjects", $ns)
|
||||
|
||||
# --- Helpers ---
|
||||
function Get-MLText($node) {
|
||||
if (-not $node) { return "" }
|
||||
$item = $node.SelectSingleNode("v8:item/v8:content", $ns)
|
||||
if ($item -and $item.InnerText) { return $item.InnerText }
|
||||
return ""
|
||||
}
|
||||
|
||||
function Get-PropText([string]$propName) {
|
||||
$n = $propsNode.SelectSingleNode("md:$propName", $ns)
|
||||
if ($n -and $n.InnerText) { return $n.InnerText }
|
||||
return ""
|
||||
}
|
||||
|
||||
function Get-PropML([string]$propName) {
|
||||
$n = $propsNode.SelectSingleNode("md:$propName", $ns)
|
||||
return (Get-MLText $n)
|
||||
}
|
||||
|
||||
# --- Type name maps (canonical order, 44 types) ---
|
||||
$typeOrder = @(
|
||||
"Language","Subsystem","StyleItem","Style",
|
||||
"CommonPicture","SessionParameter","Role","CommonTemplate",
|
||||
"FilterCriterion","CommonModule","CommonAttribute","ExchangePlan",
|
||||
"XDTOPackage","WebService","HTTPService","WSReference",
|
||||
"EventSubscription","ScheduledJob","SettingsStorage","FunctionalOption",
|
||||
"FunctionalOptionsParameter","DefinedType","CommonCommand","CommandGroup",
|
||||
"Constant","CommonForm","Catalog","Document",
|
||||
"DocumentNumerator","Sequence","DocumentJournal","Enum",
|
||||
"Report","DataProcessor","InformationRegister","AccumulationRegister",
|
||||
"ChartOfCharacteristicTypes","ChartOfAccounts","AccountingRegister",
|
||||
"ChartOfCalculationTypes","CalculationRegister",
|
||||
"BusinessProcess","Task","IntegrationService"
|
||||
)
|
||||
|
||||
$typeRuNames = @{
|
||||
"Language"="Языки"; "Subsystem"="Подсистемы"; "StyleItem"="Элементы стиля"; "Style"="Стили"
|
||||
"CommonPicture"="Общие картинки"; "SessionParameter"="Параметры сеанса"; "Role"="Роли"
|
||||
"CommonTemplate"="Общие макеты"; "FilterCriterion"="Критерии отбора"; "CommonModule"="Общие модули"
|
||||
"CommonAttribute"="Общие реквизиты"; "ExchangePlan"="Планы обмена"; "XDTOPackage"="XDTO-пакеты"
|
||||
"WebService"="Веб-сервисы"; "HTTPService"="HTTP-сервисы"; "WSReference"="WS-ссылки"
|
||||
"EventSubscription"="Подписки на события"; "ScheduledJob"="Регламентные задания"
|
||||
"SettingsStorage"="Хранилища настроек"; "FunctionalOption"="Функциональные опции"
|
||||
"FunctionalOptionsParameter"="Параметры ФО"; "DefinedType"="Определяемые типы"
|
||||
"CommonCommand"="Общие команды"; "CommandGroup"="Группы команд"; "Constant"="Константы"
|
||||
"CommonForm"="Общие формы"; "Catalog"="Справочники"; "Document"="Документы"
|
||||
"DocumentNumerator"="Нумераторы"; "Sequence"="Последовательности"; "DocumentJournal"="Журналы документов"
|
||||
"Enum"="Перечисления"; "Report"="Отчёты"; "DataProcessor"="Обработки"
|
||||
"InformationRegister"="Регистры сведений"; "AccumulationRegister"="Регистры накопления"
|
||||
"ChartOfCharacteristicTypes"="ПВХ"; "ChartOfAccounts"="Планы счетов"
|
||||
"AccountingRegister"="Регистры бухгалтерии"; "ChartOfCalculationTypes"="ПВР"
|
||||
"CalculationRegister"="Регистры расчёта"; "BusinessProcess"="Бизнес-процессы"
|
||||
"Task"="Задачи"; "IntegrationService"="Сервисы интеграции"
|
||||
}
|
||||
|
||||
# --- Read panel layout (Ext/ClientApplicationInterface.xml) ---
|
||||
$script:panelNames = @{
|
||||
"cbab57f2-a0f3-4f0a-89ea-4cb19570ab75" = "Открытых"
|
||||
"b553047f-c9aa-4157-978d-448ecad24248" = "Разделов"
|
||||
"13322b22-3960-4d68-93a6-fe2dd7f28ca3" = "Избранного"
|
||||
"c933ac92-92cd-459d-81cc-e0c8a83ced99" = "История"
|
||||
"b2735bd3-d822-4430-ba59-c9e869693b24" = "Функций"
|
||||
}
|
||||
|
||||
function Get-PanelsLayout {
|
||||
$configDir = [System.IO.Path]::GetDirectoryName($ConfigPath)
|
||||
$caiPath = Join-Path (Join-Path $configDir "Ext") "ClientApplicationInterface.xml"
|
||||
if (-not (Test-Path $caiPath)) { return $null }
|
||||
try { [xml]$caiDoc = Get-Content -Path $caiPath -Encoding UTF8 } catch { return $null }
|
||||
if (-not $caiDoc.DocumentElement) { return $null }
|
||||
$caiNs = New-Object System.Xml.XmlNamespaceManager($caiDoc.NameTable)
|
||||
$caiNs.AddNamespace("ca", "http://v8.1c.ru/8.2/managed-application/core")
|
||||
$layout = [ordered]@{ top=@(); left=@(); right=@(); bottom=@(); declared=@() }
|
||||
foreach ($side in @("top","left","right","bottom")) {
|
||||
foreach ($sideEl in $caiDoc.DocumentElement.SelectNodes("ca:$side", $caiNs)) {
|
||||
$slot = @()
|
||||
foreach ($u in $sideEl.SelectNodes(".//ca:panel/ca:uuid", $caiNs)) {
|
||||
$key = $u.InnerText.Trim()
|
||||
$nm = if ($script:panelNames.Contains($key)) { $script:panelNames[$key] } else { "?$key" }
|
||||
$slot += $nm
|
||||
}
|
||||
if ($slot.Count -gt 0) { $layout[$side] += ,$slot }
|
||||
}
|
||||
}
|
||||
foreach ($pd in $caiDoc.DocumentElement.SelectNodes("ca:panelDef", $caiNs)) {
|
||||
$key = $pd.GetAttribute("id")
|
||||
$nm = if ($script:panelNames.Contains($key)) { $script:panelNames[$key] } else { "?$key" }
|
||||
$layout.declared += $nm
|
||||
}
|
||||
return $layout
|
||||
}
|
||||
|
||||
function Format-LayoutSlots($slots) {
|
||||
# slots is array of arrays (each inner array = one side-tag's panels, may be 1+)
|
||||
# Single inner array, single panel -> just name
|
||||
# Single inner array, multiple panels -> "Стек(a, b)"
|
||||
# Multiple inner arrays -> separate entries joined by " | "
|
||||
if (-not $slots -or $slots.Count -eq 0) { return "" }
|
||||
$parts = @()
|
||||
foreach ($slot in $slots) {
|
||||
if ($slot.Count -eq 1) { $parts += $slot[0] }
|
||||
else { $parts += ("Стек(" + ($slot -join ", ") + ")") }
|
||||
}
|
||||
return ($parts -join " | ")
|
||||
}
|
||||
|
||||
$script:panelLayout = Get-PanelsLayout
|
||||
|
||||
# --- Read home page layout (Ext/HomePageWorkArea.xml) ---
|
||||
function Get-HomePageLayout {
|
||||
$configDir = [System.IO.Path]::GetDirectoryName($ConfigPath)
|
||||
$hpPath = Join-Path (Join-Path $configDir "Ext") "HomePageWorkArea.xml"
|
||||
if (-not (Test-Path $hpPath)) { return $null }
|
||||
try { [xml]$hpDoc = Get-Content -Path $hpPath -Encoding UTF8 } catch { return $null }
|
||||
if (-not $hpDoc.DocumentElement) { return $null }
|
||||
$hpNs = New-Object System.Xml.XmlNamespaceManager($hpDoc.NameTable)
|
||||
$hpNs.AddNamespace("hp", "http://v8.1c.ru/8.3/xcf/extrnprops")
|
||||
$hpNs.AddNamespace("xr", "http://v8.1c.ru/8.3/xcf/readable")
|
||||
$result = [ordered]@{ template = ""; left = @(); right = @() }
|
||||
$tmplNode = $hpDoc.DocumentElement.SelectSingleNode("hp:WorkingAreaTemplate", $hpNs)
|
||||
if ($tmplNode) { $result.template = $tmplNode.InnerText.Trim() }
|
||||
foreach ($colName in @("LeftColumn","RightColumn")) {
|
||||
$colNode = $hpDoc.DocumentElement.SelectSingleNode("hp:$colName", $hpNs)
|
||||
if (-not $colNode) { continue }
|
||||
$items = @()
|
||||
foreach ($item in $colNode.SelectNodes("hp:Item", $hpNs)) {
|
||||
$f = $item.SelectSingleNode("hp:Form", $hpNs)
|
||||
$h = $item.SelectSingleNode("hp:Height", $hpNs)
|
||||
$visNode = $item.SelectSingleNode("hp:Visibility", $hpNs)
|
||||
$common = $true
|
||||
$roles = @()
|
||||
if ($visNode) {
|
||||
$cn = $visNode.SelectSingleNode("xr:Common", $hpNs)
|
||||
if ($cn) { $common = ($cn.InnerText.Trim() -eq "true") }
|
||||
foreach ($v in $visNode.SelectNodes("xr:Value", $hpNs)) {
|
||||
$roles += @{ name = $v.GetAttribute("name"); value = ($v.InnerText.Trim() -eq "true") }
|
||||
}
|
||||
}
|
||||
$items += [ordered]@{
|
||||
form = if ($f) { $f.InnerText.Trim() } else { "" }
|
||||
height = if ($h) { [int]$h.InnerText.Trim() } else { 10 }
|
||||
common = $common
|
||||
roles = $roles
|
||||
}
|
||||
}
|
||||
if ($colName -eq "LeftColumn") { $result.left = $items } else { $result.right = $items }
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
$script:homePage = Get-HomePageLayout
|
||||
|
||||
function Format-HomePageItem($it, [bool]$detailed) {
|
||||
$badges = @()
|
||||
$badges += "h=$($it.height)"
|
||||
if (-not $it.common) { $badges += "скрыта" }
|
||||
if ($it.roles.Count -gt 0) {
|
||||
if ($detailed) { $badges += "роли: $($it.roles.Count)" }
|
||||
else { $badges += "+$($it.roles.Count) ролей" }
|
||||
}
|
||||
$tail = if ($badges.Count -gt 0) { " (" + ($badges -join ", ") + ")" } else { "" }
|
||||
return " $($it.form)$tail"
|
||||
}
|
||||
|
||||
# --- Count objects in ChildObjects ---
|
||||
$objectCounts = [ordered]@{}
|
||||
$totalObjects = 0
|
||||
|
||||
if ($childObjNode) {
|
||||
foreach ($child in $childObjNode.ChildNodes) {
|
||||
if ($child.NodeType -ne 'Element') { continue }
|
||||
$typeName = $child.LocalName
|
||||
if (-not $objectCounts.Contains($typeName)) {
|
||||
$objectCounts[$typeName] = 0
|
||||
}
|
||||
$objectCounts[$typeName] = $objectCounts[$typeName] + 1
|
||||
$totalObjects++
|
||||
}
|
||||
}
|
||||
|
||||
# --- Read key properties ---
|
||||
$cfgName = Get-PropText "Name"
|
||||
$cfgSynonym = Get-PropML "Synonym"
|
||||
$cfgVersion = Get-PropText "Version"
|
||||
$cfgVendor = Get-PropText "Vendor"
|
||||
$cfgCompat = Get-PropText "CompatibilityMode"
|
||||
$cfgExtCompat = Get-PropText "ConfigurationExtensionCompatibilityMode"
|
||||
$cfgDefaultRun = Get-PropText "DefaultRunMode"
|
||||
$cfgScript = Get-PropText "ScriptVariant"
|
||||
$cfgDefaultLang = Get-PropText "DefaultLanguage"
|
||||
$cfgDataLock = Get-PropText "DataLockControlMode"
|
||||
$dash = [char]0x2014
|
||||
$cfgModality = Get-PropText "ModalityUseMode"
|
||||
$cfgIntfCompat = Get-PropText "InterfaceCompatibilityMode"
|
||||
$cfgAutoNum = Get-PropText "ObjectAutonumerationMode"
|
||||
$cfgSyncCalls = Get-PropText "SynchronousPlatformExtensionAndAddInCallUseMode"
|
||||
$cfgDbSpaces = Get-PropText "DatabaseTablespacesUseMode"
|
||||
$cfgWindowMode = Get-PropText "MainClientApplicationWindowMode"
|
||||
|
||||
# --- BRIEF mode ---
|
||||
if ($Mode -eq "brief" -and -not $Section) {
|
||||
$synPart = if ($cfgSynonym) { " $dash `"$cfgSynonym`"" } else { "" }
|
||||
$verPart = if ($cfgVersion) { " v$cfgVersion" } else { "" }
|
||||
$compatPart = if ($cfgCompat) { " | $cfgCompat" } else { "" }
|
||||
Out "Конфигурация: ${cfgName}${synPart}${verPart} | $totalObjects объектов${compatPart}"
|
||||
}
|
||||
|
||||
# --- OVERVIEW mode ---
|
||||
if ($Mode -eq "overview" -and -not $Section) {
|
||||
$synPart = if ($cfgSynonym) { " $dash `"$cfgSynonym`"" } else { "" }
|
||||
$verPart = if ($cfgVersion) { " v$cfgVersion" } else { "" }
|
||||
Out "=== Конфигурация: ${cfgName}${synPart}${verPart} ==="
|
||||
Out ""
|
||||
|
||||
# Key properties
|
||||
Out "Формат: $version"
|
||||
if ($cfgVendor) { Out "Поставщик: $cfgVendor" }
|
||||
if ($cfgVersion) { Out "Версия: $cfgVersion" }
|
||||
Out "Совместимость: $cfgCompat"
|
||||
Out "Режим запуска: $cfgDefaultRun"
|
||||
Out "Язык скриптов: $cfgScript"
|
||||
Out "Язык: $cfgDefaultLang"
|
||||
Out "Блокировки: $cfgDataLock"
|
||||
Out "Модальность: $cfgModality"
|
||||
Out "Интерфейс: $cfgIntfCompat"
|
||||
Out ""
|
||||
|
||||
# Panel layout (if file exists)
|
||||
if ($script:panelLayout) {
|
||||
$hasPlaced = $false
|
||||
foreach ($s in @("top","left","right","bottom")) {
|
||||
if ($script:panelLayout[$s].Count -gt 0) { $hasPlaced = $true; break }
|
||||
}
|
||||
if ($hasPlaced) {
|
||||
Out "--- Раскладка панелей ---"
|
||||
foreach ($s in @("top","left","right","bottom")) {
|
||||
if ($script:panelLayout[$s].Count -gt 0) {
|
||||
Out " $($s.PadRight(7)) $(Format-LayoutSlots $script:panelLayout[$s])"
|
||||
}
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
}
|
||||
|
||||
# Home page layout (brief summary)
|
||||
if ($script:homePage) {
|
||||
$ln = $script:homePage.left.Count
|
||||
$rn = $script:homePage.right.Count
|
||||
Out "--- Начальная страница ---"
|
||||
Out " Шаблон: $($script:homePage.template)"
|
||||
Out " LeftColumn: $ln, RightColumn: $rn (детали: -Section home-page)"
|
||||
Out ""
|
||||
}
|
||||
|
||||
# Object counts table
|
||||
Out "--- Состав ($totalObjects объектов) ---"
|
||||
Out ""
|
||||
$maxTypeLen = 0
|
||||
foreach ($typeName in $typeOrder) {
|
||||
if ($objectCounts.Contains($typeName)) {
|
||||
$ruName = $typeRuNames[$typeName]
|
||||
if ($ruName.Length -gt $maxTypeLen) { $maxTypeLen = $ruName.Length }
|
||||
}
|
||||
}
|
||||
if ($maxTypeLen -lt 10) { $maxTypeLen = 10 }
|
||||
|
||||
foreach ($typeName in $typeOrder) {
|
||||
if ($objectCounts.Contains($typeName)) {
|
||||
$count = $objectCounts[$typeName]
|
||||
$ruName = $typeRuNames[$typeName]
|
||||
$padded = $ruName.PadRight($maxTypeLen)
|
||||
Out " $padded $count"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Drill-down: -Section home-page ---
|
||||
if ($Section -eq "home-page") {
|
||||
if (-not $script:homePage) {
|
||||
Out "Файл Ext/HomePageWorkArea.xml не найден"
|
||||
} else {
|
||||
Out "=== Начальная страница: $cfgName ==="
|
||||
Out ""
|
||||
Out "Шаблон: $($script:homePage.template)"
|
||||
Out ""
|
||||
foreach ($side in @(@("LeftColumn","left"), @("RightColumn","right"))) {
|
||||
$items = $script:homePage[$side[1]]
|
||||
$lbl = $side[0]
|
||||
if ($items.Count -eq 0) { Out "${lbl}: —"; Out ""; continue }
|
||||
Out "${lbl} ($($items.Count)):"
|
||||
foreach ($it in $items) {
|
||||
Out (Format-HomePageItem $it $true)
|
||||
foreach ($r in $it.roles) {
|
||||
$rval = if ($r.value) { "true" } else { "false" }
|
||||
Out " $($r.name): $rval"
|
||||
}
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- FULL mode ---
|
||||
if ($Mode -eq "full" -and -not $Section) {
|
||||
$synPart = if ($cfgSynonym) { " $dash `"$cfgSynonym`"" } else { "" }
|
||||
$verPart = if ($cfgVersion) { " v$cfgVersion" } else { "" }
|
||||
Out "=== Конфигурация: ${cfgName}${synPart}${verPart} ==="
|
||||
Out ""
|
||||
|
||||
# --- Section: Identification ---
|
||||
Out "--- Идентификация ---"
|
||||
Out "UUID: $($cfgNode.GetAttribute('uuid'))"
|
||||
Out "Имя: $cfgName"
|
||||
if ($cfgSynonym) { Out "Синоним: $cfgSynonym" }
|
||||
$cfgComment = Get-PropText "Comment"
|
||||
if ($cfgComment) { Out "Комментарий: $cfgComment" }
|
||||
$cfgPrefix = Get-PropText "NamePrefix"
|
||||
if ($cfgPrefix) { Out "Префикс: $cfgPrefix" }
|
||||
if ($cfgVendor) { Out "Поставщик: $cfgVendor" }
|
||||
if ($cfgVersion) { Out "Версия: $cfgVersion" }
|
||||
$cfgUpdateAddr = Get-PropText "UpdateCatalogAddress"
|
||||
if ($cfgUpdateAddr) { Out "Каталог обн.: $cfgUpdateAddr" }
|
||||
Out ""
|
||||
|
||||
# --- Section: Modes ---
|
||||
Out "--- Режимы работы ---"
|
||||
Out "Формат: $version"
|
||||
Out "Совместимость: $cfgCompat"
|
||||
Out "Совм. расширений: $cfgExtCompat"
|
||||
Out "Режим запуска: $cfgDefaultRun"
|
||||
Out "Язык скриптов: $cfgScript"
|
||||
Out "Блокировки: $cfgDataLock"
|
||||
Out "Автонумерация: $cfgAutoNum"
|
||||
Out "Модальность: $cfgModality"
|
||||
Out "Синхр. вызовы: $cfgSyncCalls"
|
||||
Out "Интерфейс: $cfgIntfCompat"
|
||||
Out "Табл. пространства: $cfgDbSpaces"
|
||||
Out "Режим окна: $cfgWindowMode"
|
||||
Out ""
|
||||
|
||||
# --- Section: Language, roles, purposes ---
|
||||
Out "--- Назначение ---"
|
||||
Out "Язык по умолч.: $cfgDefaultLang"
|
||||
|
||||
# UsePurposes
|
||||
$purposeNode = $propsNode.SelectSingleNode("md:UsePurposes", $ns)
|
||||
if ($purposeNode) {
|
||||
$purposes = @()
|
||||
foreach ($val in $purposeNode.SelectNodes("v8:Value", $ns)) {
|
||||
$purposes += $val.InnerText
|
||||
}
|
||||
if ($purposes.Count -gt 0) { Out "Назначения: $($purposes -join ', ')" }
|
||||
}
|
||||
|
||||
# DefaultRoles
|
||||
$rolesNode = $propsNode.SelectSingleNode("md:DefaultRoles", $ns)
|
||||
if ($rolesNode) {
|
||||
$roles = @()
|
||||
foreach ($item in $rolesNode.SelectNodes("xr:Item", $ns)) {
|
||||
$roles += $item.InnerText
|
||||
}
|
||||
if ($roles.Count -gt 0) {
|
||||
Out "Роли по умолч.: $($roles.Count)"
|
||||
foreach ($r in $roles) { Out " - $r" }
|
||||
}
|
||||
}
|
||||
|
||||
# Booleans
|
||||
$useMF = Get-PropText "UseManagedFormInOrdinaryApplication"
|
||||
$useOF = Get-PropText "UseOrdinaryFormInManagedApplication"
|
||||
Out "Управл.формы в обычн.: $useMF"
|
||||
Out "Обычн.формы в управл.: $useOF"
|
||||
Out ""
|
||||
|
||||
# --- Section: Panel layout ---
|
||||
if ($script:panelLayout) {
|
||||
Out "--- Раскладка панелей ---"
|
||||
foreach ($s in @("top","left","right","bottom")) {
|
||||
$slots = $script:panelLayout[$s]
|
||||
if ($slots.Count -gt 0) {
|
||||
Out " $($s.PadRight(7)) $(Format-LayoutSlots $slots)"
|
||||
} else {
|
||||
Out " $($s.PadRight(7)) —"
|
||||
}
|
||||
}
|
||||
if ($script:panelLayout.declared.Count -gt 0) {
|
||||
Out " объявлено: $($script:panelLayout.declared -join ', ')"
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
|
||||
# --- Section: Home page (brief summary) ---
|
||||
if ($script:homePage) {
|
||||
$ln = $script:homePage.left.Count
|
||||
$rn = $script:homePage.right.Count
|
||||
Out "--- Начальная страница ---"
|
||||
Out " Шаблон: $($script:homePage.template)"
|
||||
Out " LeftColumn: $ln, RightColumn: $rn (детали: -Section home-page)"
|
||||
Out ""
|
||||
}
|
||||
|
||||
# --- Section: Storages & default forms ---
|
||||
Out "--- Хранилища и формы по умолчанию ---"
|
||||
$storageProps = @("CommonSettingsStorage","ReportsUserSettingsStorage","ReportsVariantsStorage","FormDataSettingsStorage","DynamicListsUserSettingsStorage","URLExternalDataStorage")
|
||||
foreach ($sp in $storageProps) {
|
||||
$val = Get-PropText $sp
|
||||
if ($val) { Out " ${sp}: $val" }
|
||||
}
|
||||
$formProps = @("DefaultReportForm","DefaultReportVariantForm","DefaultReportSettingsForm","DefaultReportAppearanceTemplate","DefaultDynamicListSettingsForm","DefaultSearchForm","DefaultDataHistoryChangeHistoryForm","DefaultDataHistoryVersionDataForm","DefaultDataHistoryVersionDifferencesForm","DefaultCollaborationSystemUsersChoiceForm","DefaultConstantsForm","DefaultInterface","DefaultStyle")
|
||||
foreach ($fp in $formProps) {
|
||||
$val = Get-PropText $fp
|
||||
if ($val) { Out " ${fp}: $val" }
|
||||
}
|
||||
Out ""
|
||||
|
||||
# --- Section: Info ---
|
||||
$cfgBrief = Get-PropML "BriefInformation"
|
||||
$cfgDetail = Get-PropML "DetailedInformation"
|
||||
$cfgCopyright = Get-PropML "Copyright"
|
||||
$cfgVendorAddr = Get-PropML "VendorInformationAddress"
|
||||
$cfgInfoAddr = Get-PropML "ConfigurationInformationAddress"
|
||||
if ($cfgBrief -or $cfgDetail -or $cfgCopyright -or $cfgVendorAddr -or $cfgInfoAddr) {
|
||||
Out "--- Информация ---"
|
||||
if ($cfgBrief) { Out "Краткая: $cfgBrief" }
|
||||
if ($cfgDetail) { Out "Подробная: $cfgDetail" }
|
||||
if ($cfgCopyright) { Out "Copyright: $cfgCopyright" }
|
||||
if ($cfgVendorAddr) { Out "Сайт поставщика: $cfgVendorAddr" }
|
||||
if ($cfgInfoAddr) { Out "Адрес информ.: $cfgInfoAddr" }
|
||||
Out ""
|
||||
}
|
||||
|
||||
# --- Section: Mobile functionalities ---
|
||||
$mobileFunc = $propsNode.SelectSingleNode("md:UsedMobileApplicationFunctionalities", $ns)
|
||||
if ($mobileFunc) {
|
||||
$enabledFuncs = @()
|
||||
$disabledFuncs = @()
|
||||
foreach ($func in $mobileFunc.SelectNodes("app:functionality", $ns)) {
|
||||
$fName = $func.SelectSingleNode("app:functionality", $ns)
|
||||
$fUse = $func.SelectSingleNode("app:use", $ns)
|
||||
if ($fName -and $fUse) {
|
||||
if ($fUse.InnerText -eq "true") {
|
||||
$enabledFuncs += $fName.InnerText
|
||||
} else {
|
||||
$disabledFuncs += $fName.InnerText
|
||||
}
|
||||
}
|
||||
}
|
||||
$totalFunc = $enabledFuncs.Count + $disabledFuncs.Count
|
||||
Out "--- Мобильные функциональности ($totalFunc, включено: $($enabledFuncs.Count)) ---"
|
||||
if ($enabledFuncs.Count -gt 0) {
|
||||
foreach ($f in $enabledFuncs) { Out " [+] $f" }
|
||||
}
|
||||
foreach ($f in $disabledFuncs) { Out " [-] $f" }
|
||||
Out ""
|
||||
}
|
||||
|
||||
# --- Section: InternalInfo ---
|
||||
$internalInfo = $cfgNode.SelectSingleNode("md:InternalInfo", $ns)
|
||||
if ($internalInfo) {
|
||||
$contained = $internalInfo.SelectNodes("xr:ContainedObject", $ns)
|
||||
Out "--- InternalInfo ($($contained.Count) ContainedObject) ---"
|
||||
foreach ($co in $contained) {
|
||||
$classId = $co.SelectSingleNode("xr:ClassId", $ns).InnerText
|
||||
$objectId = $co.SelectSingleNode("xr:ObjectId", $ns).InnerText
|
||||
Out " $classId -> $objectId"
|
||||
}
|
||||
Out ""
|
||||
}
|
||||
|
||||
# --- Section: ChildObjects (full list) ---
|
||||
Out "--- Состав ($totalObjects объектов) ---"
|
||||
Out ""
|
||||
|
||||
foreach ($typeName in $typeOrder) {
|
||||
if (-not $objectCounts.Contains($typeName)) { continue }
|
||||
$count = $objectCounts[$typeName]
|
||||
$ruName = $typeRuNames[$typeName]
|
||||
Out " $ruName ($typeName): $count"
|
||||
|
||||
# Collect names for this type
|
||||
$names = @()
|
||||
foreach ($child in $childObjNode.ChildNodes) {
|
||||
if ($child.NodeType -eq 'Element' -and $child.LocalName -eq $typeName) {
|
||||
$names += $child.InnerText
|
||||
}
|
||||
}
|
||||
foreach ($n in $names) { Out " $n" }
|
||||
}
|
||||
}
|
||||
|
||||
# --- Pagination and output ---
|
||||
$total = $script:lines.Count
|
||||
if ($Offset -gt 0 -or $Limit -lt $total) {
|
||||
$start = [Math]::Min($Offset, $total)
|
||||
$end = [Math]::Min($start + $Limit, $total)
|
||||
$page = $script:lines[$start..($end - 1)]
|
||||
$result = ($page -join "`n")
|
||||
if ($end -lt $total) {
|
||||
$result += "`n`n... ($end of $total lines, use -Offset $end to continue)"
|
||||
}
|
||||
} else {
|
||||
$result = ($script:lines -join "`n")
|
||||
}
|
||||
|
||||
Write-Host $result
|
||||
|
||||
if ($OutFile) {
|
||||
$utf8Bom = New-Object System.Text.UTF8Encoding $true
|
||||
[System.IO.File]::WriteAllText($OutFile, $result, $utf8Bom)
|
||||
Write-Host "`nWritten to: $OutFile"
|
||||
}
|
||||
@@ -0,0 +1,562 @@
|
||||
#!/usr/bin/env python3
|
||||
# cf-info v1.2 — Compact summary of 1C configuration root
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from collections import OrderedDict
|
||||
from lxml import etree
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
sys.stderr.reconfigure(encoding="utf-8")
|
||||
|
||||
# --- Argument parsing ---
|
||||
parser = argparse.ArgumentParser(description="Analyze 1C configuration structure", allow_abbrev=False)
|
||||
parser.add_argument("-ConfigPath", "-Path", required=True, help="Path to Configuration.xml or directory")
|
||||
parser.add_argument("-Mode", choices=["overview", "brief", "full"], default="overview", help="Output mode")
|
||||
parser.add_argument("-Section", "-Name", choices=["home-page"], default=None, help="Drill-down section (alias: -Name)")
|
||||
parser.add_argument("-Limit", type=int, default=150, help="Max lines to show")
|
||||
parser.add_argument("-Offset", type=int, default=0, help="Lines to skip")
|
||||
parser.add_argument("-OutFile", default="", help="Write output to file")
|
||||
args = parser.parse_args()
|
||||
|
||||
# --- Output helper (collect all, paginate at the end) ---
|
||||
lines_buf = []
|
||||
|
||||
def out(text=""):
|
||||
lines_buf.append(text)
|
||||
|
||||
# --- Resolve path ---
|
||||
config_path = args.ConfigPath
|
||||
if not os.path.isabs(config_path):
|
||||
config_path = os.path.join(os.getcwd(), config_path)
|
||||
|
||||
# Directory -> find Configuration.xml
|
||||
if os.path.isdir(config_path):
|
||||
candidate = os.path.join(config_path, "Configuration.xml")
|
||||
if os.path.isfile(candidate):
|
||||
config_path = candidate
|
||||
else:
|
||||
print(f"[ERROR] No Configuration.xml found in directory: {config_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.isfile(config_path):
|
||||
print(f"[ERROR] File not found: {config_path}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# --- Load XML ---
|
||||
tree = etree.parse(config_path, etree.XMLParser(remove_blank_text=False))
|
||||
xml_root = tree.getroot()
|
||||
NS = {
|
||||
"md": "http://v8.1c.ru/8.3/MDClasses",
|
||||
"v8": "http://v8.1c.ru/8.1/data/core",
|
||||
"xr": "http://v8.1c.ru/8.3/xcf/readable",
|
||||
"xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
||||
"xs": "http://www.w3.org/2001/XMLSchema",
|
||||
"app": "http://v8.1c.ru/8.2/managed-application/core",
|
||||
}
|
||||
|
||||
md_root = xml_root # root is MetaDataObject itself
|
||||
if etree.QName(md_root.tag).localname != "MetaDataObject":
|
||||
print("[ERROR] Not a valid 1C metadata XML file (no MetaDataObject root)", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
cfg_node = md_root.find("md:Configuration", NS)
|
||||
if cfg_node is None:
|
||||
print("[ERROR] No <Configuration> element found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
version = md_root.get("version", "")
|
||||
props_node = cfg_node.find("md:Properties", NS)
|
||||
child_obj_node = cfg_node.find("md:ChildObjects", NS)
|
||||
|
||||
# --- Helpers ---
|
||||
def get_ml_text(node):
|
||||
if node is None:
|
||||
return ""
|
||||
item = node.find("v8:item/v8:content", NS)
|
||||
if item is not None and item.text:
|
||||
return item.text
|
||||
return ""
|
||||
|
||||
def get_prop_text(prop_name):
|
||||
n = props_node.find(f"md:{prop_name}", NS)
|
||||
if n is not None and n.text:
|
||||
return n.text
|
||||
return ""
|
||||
|
||||
def get_prop_ml(prop_name):
|
||||
n = props_node.find(f"md:{prop_name}", NS)
|
||||
return get_ml_text(n)
|
||||
|
||||
# --- Type name maps (canonical order, 44 types) ---
|
||||
type_order = [
|
||||
"Language", "Subsystem", "StyleItem", "Style",
|
||||
"CommonPicture", "SessionParameter", "Role", "CommonTemplate",
|
||||
"FilterCriterion", "CommonModule", "CommonAttribute", "ExchangePlan",
|
||||
"XDTOPackage", "WebService", "HTTPService", "WSReference",
|
||||
"EventSubscription", "ScheduledJob", "SettingsStorage", "FunctionalOption",
|
||||
"FunctionalOptionsParameter", "DefinedType", "CommonCommand", "CommandGroup",
|
||||
"Constant", "CommonForm", "Catalog", "Document",
|
||||
"DocumentNumerator", "Sequence", "DocumentJournal", "Enum",
|
||||
"Report", "DataProcessor", "InformationRegister", "AccumulationRegister",
|
||||
"ChartOfCharacteristicTypes", "ChartOfAccounts", "AccountingRegister",
|
||||
"ChartOfCalculationTypes", "CalculationRegister",
|
||||
"BusinessProcess", "Task", "IntegrationService",
|
||||
]
|
||||
|
||||
type_ru_names = {
|
||||
"Language": "Языки", "Subsystem": "Подсистемы", "StyleItem": "Элементы стиля", "Style": "Стили",
|
||||
"CommonPicture": "Общие картинки", "SessionParameter": "Параметры сеанса", "Role": "Роли",
|
||||
"CommonTemplate": "Общие макеты", "FilterCriterion": "Критерии отбора", "CommonModule": "Общие модули",
|
||||
"CommonAttribute": "Общие реквизиты", "ExchangePlan": "Планы обмена", "XDTOPackage": "XDTO-пакеты",
|
||||
"WebService": "Веб-сервисы", "HTTPService": "HTTP-сервисы", "WSReference": "WS-ссылки",
|
||||
"EventSubscription": "Подписки на события", "ScheduledJob": "Регламентные задания",
|
||||
"SettingsStorage": "Хранилища настроек", "FunctionalOption": "Функциональные опции",
|
||||
"FunctionalOptionsParameter": "Параметры ФО", "DefinedType": "Определяемые типы",
|
||||
"CommonCommand": "Общие команды", "CommandGroup": "Группы команд", "Constant": "Константы",
|
||||
"CommonForm": "Общие формы", "Catalog": "Справочники", "Document": "Документы",
|
||||
"DocumentNumerator": "Нумераторы", "Sequence": "Последовательности", "DocumentJournal": "Журналы документов",
|
||||
"Enum": "Перечисления", "Report": "Отчёты", "DataProcessor": "Обработки",
|
||||
"InformationRegister": "Регистры сведений", "AccumulationRegister": "Регистры накопления",
|
||||
"ChartOfCharacteristicTypes": "ПВХ", "ChartOfAccounts": "Планы счетов",
|
||||
"AccountingRegister": "Регистры бухгалтерии", "ChartOfCalculationTypes": "ПВР",
|
||||
"CalculationRegister": "Регистры расчёта", "BusinessProcess": "Бизнес-процессы",
|
||||
"Task": "Задачи", "IntegrationService": "Сервисы интеграции",
|
||||
}
|
||||
|
||||
# --- Read panel layout (Ext/ClientApplicationInterface.xml) ---
|
||||
PANEL_NAMES = {
|
||||
"cbab57f2-a0f3-4f0a-89ea-4cb19570ab75": "Открытых",
|
||||
"b553047f-c9aa-4157-978d-448ecad24248": "Разделов",
|
||||
"13322b22-3960-4d68-93a6-fe2dd7f28ca3": "Избранного",
|
||||
"c933ac92-92cd-459d-81cc-e0c8a83ced99": "История",
|
||||
"b2735bd3-d822-4430-ba59-c9e869693b24": "Функций",
|
||||
}
|
||||
CAI_NS = "http://v8.1c.ru/8.2/managed-application/core"
|
||||
|
||||
def get_panels_layout():
|
||||
cfg_dir = os.path.dirname(config_path)
|
||||
cai_path = os.path.join(cfg_dir, "Ext", "ClientApplicationInterface.xml")
|
||||
if not os.path.isfile(cai_path):
|
||||
return None
|
||||
try:
|
||||
cai_tree = etree.parse(cai_path)
|
||||
except Exception:
|
||||
return None
|
||||
cai_root = cai_tree.getroot()
|
||||
layout = {"top": [], "left": [], "right": [], "bottom": [], "declared": []}
|
||||
for side in ("top", "left", "right", "bottom"):
|
||||
for side_el in cai_root.findall(f"{{{CAI_NS}}}{side}"):
|
||||
slot = []
|
||||
for u in side_el.iter(f"{{{CAI_NS}}}uuid"):
|
||||
key = (u.text or "").strip()
|
||||
slot.append(PANEL_NAMES.get(key, f"?{key}"))
|
||||
if slot:
|
||||
layout[side].append(slot)
|
||||
for pd in cai_root.findall(f"{{{CAI_NS}}}panelDef"):
|
||||
key = pd.get("id", "")
|
||||
layout["declared"].append(PANEL_NAMES.get(key, f"?{key}"))
|
||||
return layout
|
||||
|
||||
def format_layout_slots(slots):
|
||||
if not slots:
|
||||
return ""
|
||||
parts = []
|
||||
for slot in slots:
|
||||
if len(slot) == 1:
|
||||
parts.append(slot[0])
|
||||
else:
|
||||
parts.append("Стек(" + ", ".join(slot) + ")")
|
||||
return " | ".join(parts)
|
||||
|
||||
panel_layout = get_panels_layout()
|
||||
|
||||
# --- Read home page layout (Ext/HomePageWorkArea.xml) ---
|
||||
HP_NS = "http://v8.1c.ru/8.3/xcf/extrnprops"
|
||||
XR_NS_HP = "http://v8.1c.ru/8.3/xcf/readable"
|
||||
|
||||
def get_home_page_layout():
|
||||
cfg_dir = os.path.dirname(config_path)
|
||||
hp_path = os.path.join(cfg_dir, "Ext", "HomePageWorkArea.xml")
|
||||
if not os.path.isfile(hp_path):
|
||||
return None
|
||||
try:
|
||||
hp_tree = etree.parse(hp_path)
|
||||
except Exception:
|
||||
return None
|
||||
hp_root = hp_tree.getroot()
|
||||
result = {"template": "", "left": [], "right": []}
|
||||
tn = hp_root.find(f"{{{HP_NS}}}WorkingAreaTemplate")
|
||||
if tn is not None and tn.text:
|
||||
result["template"] = tn.text.strip()
|
||||
for col_name, key in (("LeftColumn", "left"), ("RightColumn", "right")):
|
||||
col = hp_root.find(f"{{{HP_NS}}}{col_name}")
|
||||
if col is None:
|
||||
continue
|
||||
items = []
|
||||
for it in col.findall(f"{{{HP_NS}}}Item"):
|
||||
f = it.find(f"{{{HP_NS}}}Form")
|
||||
h = it.find(f"{{{HP_NS}}}Height")
|
||||
vis = it.find(f"{{{HP_NS}}}Visibility")
|
||||
common = True
|
||||
roles = []
|
||||
if vis is not None:
|
||||
cn = vis.find(f"{{{XR_NS_HP}}}Common")
|
||||
if cn is not None and cn.text:
|
||||
common = cn.text.strip() == "true"
|
||||
for v in vis.findall(f"{{{XR_NS_HP}}}Value"):
|
||||
roles.append({"name": v.get("name", ""), "value": (v.text or "").strip() == "true"})
|
||||
items.append({
|
||||
"form": (f.text or "").strip() if f is not None else "",
|
||||
"height": int((h.text or "10").strip()) if h is not None else 10,
|
||||
"common": common,
|
||||
"roles": roles,
|
||||
})
|
||||
result[key] = items
|
||||
return result
|
||||
|
||||
home_page = get_home_page_layout()
|
||||
|
||||
def format_home_page_item(it, detailed):
|
||||
badges = [f"h={it['height']}"]
|
||||
if not it["common"]:
|
||||
badges.append("скрыта")
|
||||
if it["roles"]:
|
||||
badges.append(f"роли: {len(it['roles'])}" if detailed else f"+{len(it['roles'])} ролей")
|
||||
tail = f" ({', '.join(badges)})" if badges else ""
|
||||
return f" {it['form']}{tail}"
|
||||
|
||||
# --- Count objects in ChildObjects ---
|
||||
object_counts = OrderedDict()
|
||||
total_objects = 0
|
||||
|
||||
if child_obj_node is not None:
|
||||
for child in child_obj_node:
|
||||
if not isinstance(child.tag, str):
|
||||
continue # skip comments/PIs
|
||||
type_name = etree.QName(child.tag).localname
|
||||
if type_name not in object_counts:
|
||||
object_counts[type_name] = 0
|
||||
object_counts[type_name] += 1
|
||||
total_objects += 1
|
||||
|
||||
# --- Read key properties ---
|
||||
cfg_name = get_prop_text("Name")
|
||||
cfg_synonym = get_prop_ml("Synonym")
|
||||
cfg_version = get_prop_text("Version")
|
||||
cfg_vendor = get_prop_text("Vendor")
|
||||
cfg_compat = get_prop_text("CompatibilityMode")
|
||||
cfg_ext_compat = get_prop_text("ConfigurationExtensionCompatibilityMode")
|
||||
cfg_default_run = get_prop_text("DefaultRunMode")
|
||||
cfg_script = get_prop_text("ScriptVariant")
|
||||
cfg_default_lang = get_prop_text("DefaultLanguage")
|
||||
cfg_data_lock = get_prop_text("DataLockControlMode")
|
||||
dash = "\u2014"
|
||||
cfg_modality = get_prop_text("ModalityUseMode")
|
||||
cfg_intf_compat = get_prop_text("InterfaceCompatibilityMode")
|
||||
cfg_auto_num = get_prop_text("ObjectAutonumerationMode")
|
||||
cfg_sync_calls = get_prop_text("SynchronousPlatformExtensionAndAddInCallUseMode")
|
||||
cfg_db_spaces = get_prop_text("DatabaseTablespacesUseMode")
|
||||
cfg_window_mode = get_prop_text("MainClientApplicationWindowMode")
|
||||
|
||||
# --- BRIEF mode ---
|
||||
if args.Mode == "brief" and not args.Section:
|
||||
syn_part = f' {dash} "{cfg_synonym}"' if cfg_synonym else ""
|
||||
ver_part = f" v{cfg_version}" if cfg_version else ""
|
||||
compat_part = f" | {cfg_compat}" if cfg_compat else ""
|
||||
out(f"Конфигурация: {cfg_name}{syn_part}{ver_part} | {total_objects} объектов{compat_part}")
|
||||
|
||||
# --- OVERVIEW mode ---
|
||||
if args.Mode == "overview" and not args.Section:
|
||||
syn_part = f' {dash} "{cfg_synonym}"' if cfg_synonym else ""
|
||||
ver_part = f" v{cfg_version}" if cfg_version else ""
|
||||
out(f"=== Конфигурация: {cfg_name}{syn_part}{ver_part} ===")
|
||||
out()
|
||||
|
||||
# Key properties
|
||||
out(f"Формат: {version}")
|
||||
if cfg_vendor:
|
||||
out(f"Поставщик: {cfg_vendor}")
|
||||
if cfg_version:
|
||||
out(f"Версия: {cfg_version}")
|
||||
out(f"Совместимость: {cfg_compat}")
|
||||
out(f"Режим запуска: {cfg_default_run}")
|
||||
out(f"Язык скриптов: {cfg_script}")
|
||||
out(f"Язык: {cfg_default_lang}")
|
||||
out(f"Блокировки: {cfg_data_lock}")
|
||||
out(f"Модальность: {cfg_modality}")
|
||||
out(f"Интерфейс: {cfg_intf_compat}")
|
||||
out()
|
||||
|
||||
if panel_layout and any(panel_layout[s] for s in ("top", "left", "right", "bottom")):
|
||||
out("--- Раскладка панелей ---")
|
||||
for s in ("top", "left", "right", "bottom"):
|
||||
if panel_layout[s]:
|
||||
out(f" {s.ljust(7)} {format_layout_slots(panel_layout[s])}")
|
||||
out()
|
||||
|
||||
# Home page (brief summary)
|
||||
if home_page:
|
||||
out("--- Начальная страница ---")
|
||||
out(f" Шаблон: {home_page['template']}")
|
||||
out(f" LeftColumn: {len(home_page['left'])}, RightColumn: {len(home_page['right'])} (детали: -Section home-page)")
|
||||
out()
|
||||
|
||||
# Object counts table
|
||||
out(f"--- Состав ({total_objects} объектов) ---")
|
||||
out()
|
||||
max_type_len = 0
|
||||
for type_name in type_order:
|
||||
if type_name in object_counts:
|
||||
ru_name = type_ru_names.get(type_name, type_name)
|
||||
if len(ru_name) > max_type_len:
|
||||
max_type_len = len(ru_name)
|
||||
if max_type_len < 10:
|
||||
max_type_len = 10
|
||||
|
||||
for type_name in type_order:
|
||||
if type_name in object_counts:
|
||||
count = object_counts[type_name]
|
||||
ru_name = type_ru_names.get(type_name, type_name)
|
||||
padded = ru_name.ljust(max_type_len)
|
||||
out(f" {padded} {count}")
|
||||
|
||||
# --- FULL mode ---
|
||||
# --- Drill-down: -Section home-page ---
|
||||
if args.Section == "home-page":
|
||||
if not home_page:
|
||||
out("Файл Ext/HomePageWorkArea.xml не найден")
|
||||
else:
|
||||
out(f"=== Начальная страница: {cfg_name} ===")
|
||||
out()
|
||||
out(f"Шаблон: {home_page['template']}")
|
||||
out()
|
||||
for col_lbl, col_key in (("LeftColumn", "left"), ("RightColumn", "right")):
|
||||
items = home_page[col_key]
|
||||
if not items:
|
||||
out(f"{col_lbl}: —")
|
||||
out()
|
||||
continue
|
||||
out(f"{col_lbl} ({len(items)}):")
|
||||
for it in items:
|
||||
out(format_home_page_item(it, True))
|
||||
for r in it["roles"]:
|
||||
rval = "true" if r["value"] else "false"
|
||||
out(f" {r['name']}: {rval}")
|
||||
out()
|
||||
|
||||
if args.Mode == "full" and not args.Section:
|
||||
syn_part = f' {dash} "{cfg_synonym}"' if cfg_synonym else ""
|
||||
ver_part = f" v{cfg_version}" if cfg_version else ""
|
||||
out(f"=== Конфигурация: {cfg_name}{syn_part}{ver_part} ===")
|
||||
out()
|
||||
|
||||
# --- Section: Identification ---
|
||||
out("--- Идентификация ---")
|
||||
out(f"UUID: {cfg_node.get('uuid', '')}")
|
||||
out(f"Имя: {cfg_name}")
|
||||
if cfg_synonym:
|
||||
out(f"Синоним: {cfg_synonym}")
|
||||
cfg_comment = get_prop_text("Comment")
|
||||
if cfg_comment:
|
||||
out(f"Комментарий: {cfg_comment}")
|
||||
cfg_prefix = get_prop_text("NamePrefix")
|
||||
if cfg_prefix:
|
||||
out(f"Префикс: {cfg_prefix}")
|
||||
if cfg_vendor:
|
||||
out(f"Поставщик: {cfg_vendor}")
|
||||
if cfg_version:
|
||||
out(f"Версия: {cfg_version}")
|
||||
cfg_update_addr = get_prop_text("UpdateCatalogAddress")
|
||||
if cfg_update_addr:
|
||||
out(f"Каталог обн.: {cfg_update_addr}")
|
||||
out()
|
||||
|
||||
# --- Section: Modes ---
|
||||
out("--- Режимы работы ---")
|
||||
out(f"Формат: {version}")
|
||||
out(f"Совместимость: {cfg_compat}")
|
||||
out(f"Совм. расширений: {cfg_ext_compat}")
|
||||
out(f"Режим запуска: {cfg_default_run}")
|
||||
out(f"Язык скриптов: {cfg_script}")
|
||||
out(f"Блокировки: {cfg_data_lock}")
|
||||
out(f"Автонумерация: {cfg_auto_num}")
|
||||
out(f"Модальность: {cfg_modality}")
|
||||
out(f"Синхр. вызовы: {cfg_sync_calls}")
|
||||
out(f"Интерфейс: {cfg_intf_compat}")
|
||||
out(f"Табл. пространства: {cfg_db_spaces}")
|
||||
out(f"Режим окна: {cfg_window_mode}")
|
||||
out()
|
||||
|
||||
# --- Section: Language, roles, purposes ---
|
||||
out("--- Назначение ---")
|
||||
out(f"Язык по умолч.: {cfg_default_lang}")
|
||||
|
||||
# UsePurposes
|
||||
purpose_node = props_node.find("md:UsePurposes", NS)
|
||||
if purpose_node is not None:
|
||||
purposes = []
|
||||
for val in purpose_node.findall("v8:Value", NS):
|
||||
if val.text:
|
||||
purposes.append(val.text)
|
||||
if purposes:
|
||||
out(f"Назначения: {', '.join(purposes)}")
|
||||
|
||||
# DefaultRoles
|
||||
roles_node = props_node.find("md:DefaultRoles", NS)
|
||||
if roles_node is not None:
|
||||
roles = []
|
||||
for item in roles_node.findall("xr:Item", NS):
|
||||
if item.text:
|
||||
roles.append(item.text)
|
||||
if roles:
|
||||
out(f"Роли по умолч.: {len(roles)}")
|
||||
for r in roles:
|
||||
out(f" - {r}")
|
||||
|
||||
# Booleans
|
||||
use_mf = get_prop_text("UseManagedFormInOrdinaryApplication")
|
||||
use_of = get_prop_text("UseOrdinaryFormInManagedApplication")
|
||||
out(f"Управл.формы в обычн.: {use_mf}")
|
||||
out(f"Обычн.формы в управл.: {use_of}")
|
||||
out()
|
||||
|
||||
# --- Section: Panel layout ---
|
||||
if panel_layout:
|
||||
out("--- Раскладка панелей ---")
|
||||
for s in ("top", "left", "right", "bottom"):
|
||||
slots = panel_layout[s]
|
||||
if slots:
|
||||
out(f" {s.ljust(7)} {format_layout_slots(slots)}")
|
||||
else:
|
||||
out(f" {s.ljust(7)} —")
|
||||
if panel_layout["declared"]:
|
||||
out(f" объявлено: {', '.join(panel_layout['declared'])}")
|
||||
out()
|
||||
|
||||
# --- Section: Home page (brief summary) ---
|
||||
if home_page:
|
||||
out("--- Начальная страница ---")
|
||||
out(f" Шаблон: {home_page['template']}")
|
||||
out(f" LeftColumn: {len(home_page['left'])}, RightColumn: {len(home_page['right'])} (детали: -Section home-page)")
|
||||
out()
|
||||
|
||||
# --- Section: Storages & default forms ---
|
||||
out("--- Хранилища и формы по умолчанию ---")
|
||||
storage_props = [
|
||||
"CommonSettingsStorage", "ReportsUserSettingsStorage", "ReportsVariantsStorage",
|
||||
"FormDataSettingsStorage", "DynamicListsUserSettingsStorage", "URLExternalDataStorage",
|
||||
]
|
||||
for sp in storage_props:
|
||||
val = get_prop_text(sp)
|
||||
if val:
|
||||
out(f" {sp}: {val}")
|
||||
form_props = [
|
||||
"DefaultReportForm", "DefaultReportVariantForm", "DefaultReportSettingsForm",
|
||||
"DefaultReportAppearanceTemplate", "DefaultDynamicListSettingsForm", "DefaultSearchForm",
|
||||
"DefaultDataHistoryChangeHistoryForm", "DefaultDataHistoryVersionDataForm",
|
||||
"DefaultDataHistoryVersionDifferencesForm", "DefaultCollaborationSystemUsersChoiceForm",
|
||||
"DefaultConstantsForm", "DefaultInterface", "DefaultStyle",
|
||||
]
|
||||
for fp in form_props:
|
||||
val = get_prop_text(fp)
|
||||
if val:
|
||||
out(f" {fp}: {val}")
|
||||
out()
|
||||
|
||||
# --- Section: Info ---
|
||||
cfg_brief = get_prop_ml("BriefInformation")
|
||||
cfg_detail = get_prop_ml("DetailedInformation")
|
||||
cfg_copyright = get_prop_ml("Copyright")
|
||||
cfg_vendor_addr = get_prop_ml("VendorInformationAddress")
|
||||
cfg_info_addr = get_prop_ml("ConfigurationInformationAddress")
|
||||
if cfg_brief or cfg_detail or cfg_copyright or cfg_vendor_addr or cfg_info_addr:
|
||||
out("--- Информация ---")
|
||||
if cfg_brief:
|
||||
out(f"Краткая: {cfg_brief}")
|
||||
if cfg_detail:
|
||||
out(f"Подробная: {cfg_detail}")
|
||||
if cfg_copyright:
|
||||
out(f"Copyright: {cfg_copyright}")
|
||||
if cfg_vendor_addr:
|
||||
out(f"Сайт поставщика: {cfg_vendor_addr}")
|
||||
if cfg_info_addr:
|
||||
out(f"Адрес информ.: {cfg_info_addr}")
|
||||
out()
|
||||
|
||||
# --- Section: Mobile functionalities ---
|
||||
mobile_func = props_node.find("md:UsedMobileApplicationFunctionalities", NS)
|
||||
if mobile_func is not None:
|
||||
enabled_funcs = []
|
||||
disabled_funcs = []
|
||||
for func in mobile_func.findall("app:functionality", NS):
|
||||
f_name = func.find("app:functionality", NS)
|
||||
f_use = func.find("app:use", NS)
|
||||
if f_name is not None and f_use is not None:
|
||||
if f_use.text == "true":
|
||||
enabled_funcs.append(f_name.text or "")
|
||||
else:
|
||||
disabled_funcs.append(f_name.text or "")
|
||||
total_func = len(enabled_funcs) + len(disabled_funcs)
|
||||
out(f"--- Мобильные функциональности ({total_func}, включено: {len(enabled_funcs)}) ---")
|
||||
for f in enabled_funcs:
|
||||
out(f" [+] {f}")
|
||||
for f in disabled_funcs:
|
||||
out(f" [-] {f}")
|
||||
out()
|
||||
|
||||
# --- Section: InternalInfo ---
|
||||
internal_info = cfg_node.find("md:InternalInfo", NS)
|
||||
if internal_info is not None:
|
||||
contained = internal_info.findall("xr:ContainedObject", NS)
|
||||
out(f"--- InternalInfo ({len(contained)} ContainedObject) ---")
|
||||
for co in contained:
|
||||
class_id_node = co.find("xr:ClassId", NS)
|
||||
object_id_node = co.find("xr:ObjectId", NS)
|
||||
class_id = class_id_node.text if class_id_node is not None else ""
|
||||
object_id = object_id_node.text if object_id_node is not None else ""
|
||||
out(f" {class_id} -> {object_id}")
|
||||
out()
|
||||
|
||||
# --- Section: ChildObjects (full list) ---
|
||||
out(f"--- Состав ({total_objects} объектов) ---")
|
||||
out()
|
||||
|
||||
for type_name in type_order:
|
||||
if type_name not in object_counts:
|
||||
continue
|
||||
count = object_counts[type_name]
|
||||
ru_name = type_ru_names.get(type_name, type_name)
|
||||
out(f" {ru_name} ({type_name}): {count}")
|
||||
|
||||
# Collect names for this type
|
||||
if child_obj_node is not None:
|
||||
for child in child_obj_node:
|
||||
if not isinstance(child.tag, str):
|
||||
continue
|
||||
if etree.QName(child.tag).localname == type_name:
|
||||
out(f" {child.text or ''}")
|
||||
|
||||
# --- Pagination and output ---
|
||||
total = len(lines_buf)
|
||||
if args.Offset > 0 or args.Limit < total:
|
||||
start = min(args.Offset, total)
|
||||
end = min(start + args.Limit, total)
|
||||
page = lines_buf[start:end]
|
||||
result = "\n".join(page)
|
||||
if end < total:
|
||||
result += f"\n\n... ({end} of {total} lines, use -Offset {end} to continue)"
|
||||
else:
|
||||
result = "\n".join(lines_buf)
|
||||
|
||||
print(result)
|
||||
|
||||
if args.OutFile:
|
||||
out_file = args.OutFile
|
||||
if not os.path.isabs(out_file):
|
||||
out_file = os.path.join(os.getcwd(), out_file)
|
||||
with open(out_file, "w", encoding="utf-8-sig") as f:
|
||||
f.write(result)
|
||||
print(f"\nWritten to: {out_file}")
|
||||
Reference in New Issue
Block a user