124 lines
4.5 KiB
PowerShell
124 lines
4.5 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[string]$OutputDirectory = ''
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$projectRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
|
|
if (-not $OutputDirectory) {
|
|
$OutputDirectory = Join-Path $projectRoot 'dist'
|
|
}
|
|
if (-not [System.IO.Path]::IsPathRooted($OutputDirectory)) {
|
|
$OutputDirectory = Join-Path $projectRoot $OutputDirectory
|
|
}
|
|
$outputRoot = [System.IO.Path]::GetFullPath($OutputDirectory)
|
|
$projectFull = [System.IO.Path]::GetFullPath($projectRoot)
|
|
if (-not $outputRoot.StartsWith($projectFull, [StringComparison]::OrdinalIgnoreCase)) {
|
|
throw 'OutputDirectory must stay inside the N7Cockpit project.'
|
|
}
|
|
|
|
$version = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
$stagingRoot = Join-Path $outputRoot "portable-staging-$version"
|
|
$packageRoot = Join-Path $stagingRoot 'N7Cockpit'
|
|
$zipPath = Join-Path $outputRoot "N7Cockpit-portable-$version.zip"
|
|
New-Item -ItemType Directory -Force -Path $packageRoot | Out-Null
|
|
|
|
$rootFiles = @(
|
|
'.gitignore',
|
|
'build.gradle',
|
|
'gradle.properties',
|
|
'gradlew',
|
|
'gradlew.bat',
|
|
'README.md',
|
|
'MIGRATION_GUIDE.md',
|
|
'settings.gradle'
|
|
)
|
|
foreach ($relative in $rootFiles) {
|
|
Copy-Item -LiteralPath (Join-Path $projectRoot $relative) `
|
|
-Destination (Join-Path $packageRoot $relative)
|
|
}
|
|
|
|
$directoryPairs = @(
|
|
@('gradle', 'gradle'),
|
|
@('app\src', 'app\src')
|
|
)
|
|
foreach ($pair in $directoryPairs) {
|
|
$destination = Join-Path $packageRoot $pair[1]
|
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $destination) | Out-Null
|
|
Copy-Item -LiteralPath (Join-Path $projectRoot $pair[0]) `
|
|
-Destination $destination -Recurse
|
|
}
|
|
New-Item -ItemType Directory -Force -Path (Join-Path $packageRoot 'app') | Out-Null
|
|
Copy-Item -LiteralPath (Join-Path $projectRoot 'app\build.gradle') `
|
|
-Destination (Join-Path $packageRoot 'app\build.gradle')
|
|
Copy-Item -LiteralPath (Join-Path $projectRoot 'app\proguard-rules.pro') `
|
|
-Destination (Join-Path $packageRoot 'app\proguard-rules.pro')
|
|
New-Item -ItemType Directory -Force -Path (Join-Path $packageRoot 'scripts') | Out-Null
|
|
$portableScripts = @(
|
|
'initialize-migration.ps1',
|
|
'verify-migration-environment.ps1',
|
|
'check-server-a.ps1',
|
|
'test-server-a-dry-run.ps1',
|
|
'build-migrated-apk.ps1',
|
|
'install-migrated-apk.ps1',
|
|
'create-portable-package.ps1'
|
|
)
|
|
foreach ($script in $portableScripts) {
|
|
Copy-Item -LiteralPath (Join-Path $projectRoot "scripts\$script") `
|
|
-Destination (Join-Path $packageRoot "scripts\$script")
|
|
}
|
|
New-Item -ItemType Directory -Force -Path (Join-Path $packageRoot 'config') | Out-Null
|
|
Copy-Item -LiteralPath (Join-Path $projectRoot 'config\migration.example.psd1') `
|
|
-Destination (Join-Path $packageRoot 'config\migration.example.psd1')
|
|
|
|
$forbiddenNames = @(
|
|
'migration.psd1',
|
|
'device-token.txt',
|
|
'local.properties'
|
|
)
|
|
$forbidden = Get-ChildItem -Recurse -Force -File -LiteralPath $packageRoot |
|
|
Where-Object { $_.Name -in $forbiddenNames -or $_.Extension -in @('.jks', '.p12') }
|
|
if ($forbidden) {
|
|
throw "Portable package contains forbidden files: $($forbidden.FullName -join ', ')"
|
|
}
|
|
|
|
$files = Get-ChildItem -Recurse -Force -File -LiteralPath $packageRoot |
|
|
Sort-Object FullName
|
|
$manifest = [ordered]@{
|
|
package = 'N7Cockpit portable source package'
|
|
generated_at = (Get-Date).ToUniversalTime().ToString('o')
|
|
contains_credentials = $false
|
|
default_execution_target = 'dry_run'
|
|
file_count = $files.Count
|
|
files = @($files | ForEach-Object {
|
|
[ordered]@{
|
|
path = $_.FullName.Substring($packageRoot.Length + 1).Replace('\', '/')
|
|
size = $_.Length
|
|
sha256 = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash
|
|
}
|
|
})
|
|
}
|
|
$manifest | ConvertTo-Json -Depth 5 | Set-Content `
|
|
-LiteralPath (Join-Path $packageRoot 'PACKAGE-MANIFEST.json') -Encoding UTF8
|
|
|
|
Compress-Archive -LiteralPath $packageRoot -DestinationPath $zipPath `
|
|
-CompressionLevel Optimal
|
|
$zipHash = (Get-FileHash -LiteralPath $zipPath -Algorithm SHA256).Hash
|
|
$checksumPath = "$zipPath.sha256"
|
|
"$zipHash $([System.IO.Path]::GetFileName($zipPath))" | Set-Content `
|
|
-LiteralPath $checksumPath -Encoding ASCII
|
|
|
|
$resolvedStaging = [System.IO.Path]::GetFullPath($stagingRoot)
|
|
if (-not $resolvedStaging.StartsWith($outputRoot, [StringComparison]::OrdinalIgnoreCase)) {
|
|
throw 'Refusing to remove staging directory outside output root.'
|
|
}
|
|
Remove-Item -LiteralPath $resolvedStaging -Recurse -Force
|
|
|
|
[pscustomobject]@{
|
|
Passed = $true
|
|
Zip = $zipPath
|
|
Sha256 = $zipHash
|
|
ChecksumFile = $checksumPath
|
|
CredentialFilesIncluded = $false
|
|
}
|