Files
Qinventor/scripts/package.ps1
T

91 lines
6.3 KiB
PowerShell

param([switch]$SkipTests)
$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
& (Join-Path $PSScriptRoot 'build-launcher.ps1')
& (Join-Path $PSScriptRoot 'sync.ps1')
if (-not $SkipTests) { & (Join-Path $PSScriptRoot 'test.ps1') }
$report = Join-Path $root 'artifacts\validation.json'
if (-not (Test-Path -LiteralPath $report)) { throw 'Нет отчёта проверки. Сначала выполните scripts/test.ps1.' }
$validated = Get-Content -LiteralPath $report -Raw | ConvertFrom-Json
if ($validated.status -ne 'passed') { throw 'Отчёт проверки CAD содержит ошибки.' }
if ($null -eq $validated.native_exit_code -or $validated.native_exit_code -ne 0) {
throw 'Не подтверждено корректное завершение CAD-процесса. Запустите scripts/test.ps1.'
}
if (-not $validated.source_sha256 -or $validated.source_sha256.Count -eq 0) {
throw 'В отчёте проверки нет снимка исходного кода. Выполните scripts/test.ps1.'
}
# Compare the complete current set too: checking only saved entries would let
# newly added, untested commands enter a -SkipTests package unnoticed.
$currentSources = foreach ($directory in @('src', 'tests', 'scripts')) {
Get-ChildItem -LiteralPath (Join-Path $root $directory) -File -Recurse |
Where-Object {
$_.Name -notmatch '\.(pyc|FCBak)$' -and
$_.FullName.Substring($root.Length + 1) -notmatch '(^|[\\/])(bin|obj|__pycache__)([\\/]|$)'
} | ForEach-Object { $_.FullName.Substring($root.Length + 1) }
}
$validatedPaths = @($validated.source_sha256 | ForEach-Object { $_.path } | Sort-Object)
$currentPaths = @($currentSources | Sort-Object)
if (($validatedPaths -join "`n") -cne ($currentPaths -join "`n")) {
throw 'Состав исходных файлов изменился после проверки. Выполните scripts/test.ps1.'
}
foreach ($file in $validated.source_sha256) {
$current = (Get-FileHash -LiteralPath (Join-Path $root $file.path) -Algorithm SHA256).Hash.ToLowerInvariant()
if ($current -ne $file.sha256) { throw "Исходный файл изменился после проверки: $($file.path). Выполните scripts/test.ps1." }
}
$enginePath = Join-Path $root ((Get-Content -LiteralPath (Join-Path $root 'data\runtime-path.txt') -Raw).Trim())
$engineRoot = Split-Path -Parent (Split-Path -Parent $enginePath)
$workbench = Join-Path $engineRoot 'Mod\QInventor'
if (-not (Test-Path -LiteralPath $workbench)) { $workbench = Join-Path (Split-Path -Parent $enginePath) 'Mod\QInventor' }
$sourceRoot = Join-Path $root 'src\QInventor'
$sourceFiles = @(Get-ChildItem -LiteralPath $sourceRoot -File -Recurse |
Where-Object { $_.Extension -ne '.pyc' -and $_.FullName -notmatch '[\\/]__pycache__[\\/]' })
$moduleFiles = @(Get-ChildItem -LiteralPath $workbench -File -Recurse |
Where-Object { $_.Extension -ne '.pyc' -and $_.FullName -notmatch '[\\/]__pycache__[\\/]' })
$sourceNames = @($sourceFiles | ForEach-Object { $_.FullName.Substring($sourceRoot.Length + 1) } | Sort-Object)
$moduleNames = @($moduleFiles | ForEach-Object { $_.FullName.Substring($workbench.Length + 1) } | Sort-Object)
if (($sourceNames -join "`n") -cne ($moduleNames -join "`n")) {
throw 'Рабочая среда CAD содержит файлы, которых нет в проверенном снимке исходного кода.'
}
foreach ($file in $sourceFiles) {
$nativeCopy = Join-Path $workbench $file.FullName.Substring($sourceRoot.Length + 1)
if ((Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash -ne (Get-FileHash -LiteralPath $nativeCopy -Algorithm SHA256).Hash) {
throw "Рабочая среда CAD отличается от проверенного исходного кода: $($file.Name)"
}
}
$release = Join-Path $root 'release'
New-Item -ItemType Directory -Path $release -Force | Out-Null
$sourceHashes = Get-ChildItem -LiteralPath (Join-Path $root 'src') -File -Recurse |
Where-Object { $_.Extension -ne '.pyc' } | ForEach-Object {
@{ path = $_.FullName.Substring($root.Length+1); sha256 = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant() }
}
$manifest = @{
application = 'QInventor'; version = '1.0.0'; platform = 'Windows x64';
engine = 'FreeCAD 1.1.4 / Open CASCADE';
officialRuntimeArchiveSha256 = '4828741fc91ee37fafcdb97a1abacb18b04ba451ac4372d9ff7a7349b36f4d6d';
builtAtUtc = [DateTime]::UtcNow.ToString('o');
launcherSha256 = (Get-FileHash -LiteralPath (Join-Path $root 'QInventor.exe') -Algorithm SHA256).Hash.ToLowerInvariant();
validation = $validated; sources = @($sourceHashes)
}
$manifest | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath (Join-Path $root 'manifest.json') -Encoding utf8
Copy-Item -LiteralPath $report -Destination (Join-Path $release 'validation.json') -Force
$archive = Join-Path $release 'QInventor-1.0.0-win-x64-portable.zip'
if (Test-Path -LiteralPath $archive) {
Move-Item -LiteralPath $archive -Destination (Join-Path $release "QInventor-previous-$([DateTime]::Now.ToString('yyyyMMdd-HHmmss')).zip")
}
$files = @('QInventor.exe','QInventor.cmd','README.md','LICENSE','THIRD_PARTY_NOTICES.md','manifest.json',
'runtime','src','scripts','tests','docs','examples','data\runtime-path.txt')
Push-Location $root
try {
& 'C:\Program Files\7-Zip\7z.exe' a -tzip $archive @files '-xr!__pycache__' '-xr!*.pyc' '-xr!*.pdb' '-xr!*.FCStd1' '-xr!*.FCBak' '-xr!obj' '-xr!artifacts' '-x!scripts\launcher\bin\*' -mx1 -bsp0 -bso0
if ($LASTEXITCODE -ne 0) { throw 'Не удалось создать переносимый архив.' }
} finally { Pop-Location }
# Do not globally exclude bin: the runtime's bin directory contains the CAD
# executables. The launcher development bin is filtered by exact archive paths.
& 'C:\Program Files\7-Zip\7z.exe' t $archive -bsp0 -bso0
if ($LASTEXITCODE -ne 0) { throw 'Проверка целостности переносимого архива завершилась с ошибкой.' }
Get-FileHash -LiteralPath $archive -Algorithm SHA256 |
Select-Object @{Name='Алгоритм';Expression={$_.Algorithm}},
@{Name='Контрольная сумма';Expression={$_.Hash}},
@{Name='Файл';Expression={$_.Path}} | Format-List
Write-Host "Переносимый выпуск: $archive"