feat: integrate N7Cockpit remote mode control

This commit is contained in:
vee
2026-08-13 10:36:24 +08:00
parent fd3c219c39
commit 78d758d3fb
108 changed files with 23150 additions and 16 deletions
@@ -0,0 +1,123 @@
[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
}