feat.发布与打包优化

This commit is contained in:
lincube
2026-05-18 14:51:05 +08:00
parent b6d820a320
commit 68dc17f863
5 changed files with 324 additions and 7 deletions

View File

@@ -179,6 +179,7 @@ jobs:
-p:PublishSingleFile=false ` -p:PublishSingleFile=false `
-p:DebugType=none ` -p:DebugType=none `
-p:DebugSymbols=false ` -p:DebugSymbols=false `
-p:SkipAirAppHostBuild=true `
-p:PublishTrimmed=false ` -p:PublishTrimmed=false `
-p:PublishReadyToRun=false ` -p:PublishReadyToRun=false `
-p:Version=${{ needs.prepare.outputs.version }} ` -p:Version=${{ needs.prepare.outputs.version }} `
@@ -193,6 +194,7 @@ jobs:
-p:PublishSingleFile=false ` -p:PublishSingleFile=false `
-p:DebugType=none ` -p:DebugType=none `
-p:DebugSymbols=false ` -p:DebugSymbols=false `
-p:SkipAirAppHostBuild=true `
-p:PublishTrimmed=false ` -p:PublishTrimmed=false `
-p:PublishReadyToRun=false ` -p:PublishReadyToRun=false `
-p:Version=${{ needs.prepare.outputs.version }} ` -p:Version=${{ needs.prepare.outputs.version }} `
@@ -202,6 +204,48 @@ jobs:
} }
shell: pwsh shell: pwsh
- name: Publish AirAppHost
run: |
$arch = "${{ matrix.arch }}"
$selfContained = "${{ matrix.self_contained }}" -eq "true"
$publishDir = if ($selfContained) { "publish/windows-$arch" } else { "publish/windows-$arch-lite" }
if ($selfContained) {
dotnet publish LanMountainDesktop.AirAppHost/LanMountainDesktop.AirAppHost.csproj `
-c Release `
-o ./$publishDir `
--self-contained:false `
-r win-$arch `
-p:PublishSingleFile=false `
-p:DebugType=none `
-p:DebugSymbols=false `
-p:PublishTrimmed=false `
-p:PublishReadyToRun=false `
-p:BuildingAirAppHost=true `
-p:SkipAirAppHostBuild=true `
-p:Version=${{ needs.prepare.outputs.version }} `
-p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }} `
-p:FileVersion=${{ needs.prepare.outputs.assembly_version }} `
-p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}
} else {
dotnet publish LanMountainDesktop.AirAppHost/LanMountainDesktop.AirAppHost.csproj `
-c Release `
-o ./$publishDir `
--self-contained:false `
-p:PublishSingleFile=false `
-p:DebugType=none `
-p:DebugSymbols=false `
-p:PublishTrimmed=false `
-p:PublishReadyToRun=false `
-p:BuildingAirAppHost=true `
-p:SkipAirAppHostBuild=true `
-p:Version=${{ needs.prepare.outputs.version }} `
-p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }} `
-p:FileVersion=${{ needs.prepare.outputs.assembly_version }} `
-p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}
}
shell: pwsh
- name: Restructure for Launcher - name: Restructure for Launcher
run: | run: |
$version = "${{ needs.prepare.outputs.version }}" $version = "${{ needs.prepare.outputs.version }}"
@@ -227,6 +271,18 @@ jobs:
Move-Item -Path $newStructure -Destination $publishDir -Force Move-Item -Path $newStructure -Destination $publishDir -Force
shell: pwsh shell: pwsh
- name: Optimize and Guard Windows Payload
run: |
$arch = "${{ matrix.arch }}"
$selfContained = "${{ matrix.self_contained }}" -eq "true"
$publishDir = if ($selfContained) { "publish/windows-$arch" } else { "publish/windows-$arch-lite" }
./LanMountainDesktop/scripts/Optimize-PublishPayload.ps1 `
-PublishDir $publishDir `
-RuntimeIdentifier "win-$arch" `
-AssertClean
shell: pwsh
- name: Install Inno Setup and 7z - name: Install Inno Setup and 7z
run: | run: |
choco install innosetup -y --no-progress choco install innosetup -y --no-progress
@@ -418,6 +474,7 @@ jobs:
-p:SelfContained=true \ -p:SelfContained=true \
-p:DebugType=none \ -p:DebugType=none \
-p:DebugSymbols=false \ -p:DebugSymbols=false \
-p:SkipAirAppHostBuild=true \
-p:PublishTrimmed=false \ -p:PublishTrimmed=false \
-p:PublishReadyToRun=false \ -p:PublishReadyToRun=false \
-p:Version=${{ needs.prepare.outputs.version }} \ -p:Version=${{ needs.prepare.outputs.version }} \
@@ -606,6 +663,7 @@ jobs:
-p:SelfContained=true \ -p:SelfContained=true \
-p:DebugType=none \ -p:DebugType=none \
-p:DebugSymbols=false \ -p:DebugSymbols=false \
-p:SkipAirAppHostBuild=true \
-p:PublishTrimmed=false \ -p:PublishTrimmed=false \
-p:PublishReadyToRun=false \ -p:PublishReadyToRun=false \
-p:Version=${{ needs.prepare.outputs.version }} \ -p:Version=${{ needs.prepare.outputs.version }} \

View File

@@ -33,6 +33,8 @@ internal sealed class AirAppHostLocator
{ {
yield return Path.Combine(deploymentDirectory, "AirAppHost", WindowsExecutableName); yield return Path.Combine(deploymentDirectory, "AirAppHost", WindowsExecutableName);
yield return Path.Combine(deploymentDirectory, "AirAppHost", DllName); yield return Path.Combine(deploymentDirectory, "AirAppHost", DllName);
yield return Path.Combine(deploymentDirectory, WindowsExecutableName);
yield return Path.Combine(deploymentDirectory, DllName);
} }
} }
} }

View File

@@ -126,9 +126,11 @@
SkipUnchangedFiles="true" /> SkipUnchangedFiles="true" />
</Target> </Target>
<Target Name="CopyAirAppHostPublishOutput" AfterTargets="Publish" Condition="'$(PublishDir)' != ''"> <Target Name="CopyAirAppHostPublishOutput"
AfterTargets="Publish"
Condition="'$(PublishDir)' != '' and '$(AirAppHostPublishDir)' != '' and '$(SkipAirAppHostBuild)' != 'true'">
<ItemGroup> <ItemGroup>
<_AirAppHostPublishOutput Include="..\LanMountainDesktop.AirAppHost\bin\$(Configuration)\$(TargetFramework)\**\*" /> <_AirAppHostPublishOutput Include="$(AirAppHostPublishDir)\**\*" />
</ItemGroup> </ItemGroup>
<MakeDir Directories="$(PublishDir)AirAppHost" /> <MakeDir Directories="$(PublishDir)AirAppHost" />
<Copy SourceFiles="@(_AirAppHostPublishOutput)" <Copy SourceFiles="@(_AirAppHostPublishOutput)"

View File

@@ -0,0 +1,203 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$PublishDir,
[Parameter(Mandatory = $true)]
[string]$RuntimeIdentifier,
[switch]$KeepSymbols,
[switch]$AssertClean
)
$ErrorActionPreference = "Stop"
function Format-Size {
param([long]$Bytes)
if ($Bytes -ge 1GB) {
return "{0:N2} GB" -f ($Bytes / 1GB)
}
if ($Bytes -ge 1MB) {
return "{0:N2} MB" -f ($Bytes / 1MB)
}
return "{0:N2} KB" -f ($Bytes / 1KB)
}
function Get-DirectorySize {
param([Parameter(Mandatory = $true)][string]$Path)
$sum = (Get-ChildItem -LiteralPath $Path -Recurse -File -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum).Sum
if ($null -eq $sum) {
return 0
}
return [long]$sum
}
function Get-RelativePathCompat {
param(
[Parameter(Mandatory = $true)][string]$Root,
[Parameter(Mandatory = $true)][string]$Path
)
$rootPath = [System.IO.Path]::GetFullPath($Root)
if (-not $rootPath.EndsWith([System.IO.Path]::DirectorySeparatorChar)) {
$rootPath += [System.IO.Path]::DirectorySeparatorChar
}
$targetPath = [System.IO.Path]::GetFullPath($Path)
$rootUri = [System.Uri]::new($rootPath)
$targetUri = [System.Uri]::new($targetPath)
return [System.Uri]::UnescapeDataString($rootUri.MakeRelativeUri($targetUri).ToString()).Replace('/', [System.IO.Path]::DirectorySeparatorChar)
}
function Write-PayloadAudit {
param([Parameter(Mandatory = $true)][string]$Root)
$files = @(Get-ChildItem -LiteralPath $Root -Recurse -File -ErrorAction SilentlyContinue)
$totalBytes = ($files | Measure-Object -Property Length -Sum).Sum
if ($null -eq $totalBytes) {
$totalBytes = 0
}
Write-Host "Publish payload audit"
Write-Host " Root: $Root"
Write-Host " Files: $($files.Count)"
Write-Host " Total: $(Format-Size -Bytes $totalBytes)"
Write-Host "Largest files:"
$files |
Sort-Object Length -Descending |
Select-Object -First 30 |
ForEach-Object {
$relative = Get-RelativePathCompat -Root $Root -Path $_.FullName
Write-Host (" {0,10} {1}" -f (Format-Size -Bytes $_.Length), $relative)
}
Write-Host "By extension:"
$extensionGroups = @($files | Group-Object Extension)
$extensionRows = foreach ($group in $extensionGroups) {
$bytes = ($group.Group | Measure-Object -Property Length -Sum).Sum
if ($null -eq $bytes) {
$bytes = 0
}
[PSCustomObject]@{
Extension = if ([string]::IsNullOrWhiteSpace($group.Name)) { "<none>" } else { $group.Name }
Count = $group.Count
Bytes = [long]$bytes
}
}
foreach ($row in @($extensionRows | Sort-Object Bytes -Descending)) {
Write-Host (" {0,10} {1,5} {2}" -f (Format-Size -Bytes $row.Bytes), $row.Count, $row.Extension)
}
$runtimeRoots = @(Get-ChildItem -LiteralPath $Root -Recurse -Directory -Filter "runtimes" -ErrorAction SilentlyContinue)
if ($runtimeRoots.Count -gt 0) {
Write-Host "Runtime directories:"
foreach ($runtimeRoot in $runtimeRoots) {
Get-ChildItem -LiteralPath $runtimeRoot.FullName -Directory -ErrorAction SilentlyContinue |
Sort-Object Name |
ForEach-Object {
$relative = Get-RelativePathCompat -Root $Root -Path $_.FullName
Write-Host (" {0,10} {1}" -f (Format-Size -Bytes (Get-DirectorySize -Path $_.FullName)), $relative)
}
}
}
}
function Remove-PdbFiles {
param([Parameter(Mandatory = $true)][string]$Root)
if ($KeepSymbols) {
Write-Host "Keeping PDB files because -KeepSymbols was specified."
return
}
$pdbFiles = @(Get-ChildItem -LiteralPath $Root -Recurse -File -Filter "*.pdb" -ErrorAction SilentlyContinue)
foreach ($file in $pdbFiles) {
Remove-Item -LiteralPath $file.FullName -Force -ErrorAction Stop
}
Write-Host "Removed PDB files: $($pdbFiles.Count)"
}
function Remove-NonTargetRuntimeDirectories {
param(
[Parameter(Mandatory = $true)][string]$Root,
[Parameter(Mandatory = $true)][string]$Rid
)
if ($Rid -notlike "win-*") {
return
}
$runtimeRoots = @(Get-ChildItem -LiteralPath $Root -Recurse -Directory -Filter "runtimes" -ErrorAction SilentlyContinue)
$removed = 0
foreach ($runtimeRoot in $runtimeRoots) {
Get-ChildItem -LiteralPath $runtimeRoot.FullName -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne $Rid } |
ForEach-Object {
Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction Stop
$removed++
}
}
Write-Host "Removed non-target runtime directories: $removed"
}
function Assert-WindowsPayloadClean {
param(
[Parameter(Mandatory = $true)][string]$Root,
[Parameter(Mandatory = $true)][string]$Rid
)
if ($Rid -notlike "win-*") {
return
}
$violations = [System.Collections.Generic.List[string]]::new()
$forbiddenExtensions = @(".pdb", ".so", ".dylib", ".a")
Get-ChildItem -LiteralPath $Root -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $forbiddenExtensions -contains $_.Extension.ToLowerInvariant() } |
ForEach-Object {
$violations.Add((Get-RelativePathCompat -Root $Root -Path $_.FullName))
}
Get-ChildItem -LiteralPath $Root -Recurse -Directory -Filter "runtimes" -ErrorAction SilentlyContinue |
ForEach-Object {
Get-ChildItem -LiteralPath $_.FullName -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne $Rid } |
ForEach-Object {
$violations.Add((Get-RelativePathCompat -Root $Root -Path $_.FullName))
}
}
if ($violations.Count -gt 0) {
$sample = ($violations | Select-Object -First 50) -join [Environment]::NewLine
throw "Windows publish payload contains forbidden files or runtime directories for ${Rid}:$([Environment]::NewLine)$sample"
}
Write-Host "Windows payload guard passed for $Rid."
}
$resolvedPublishDir = [System.IO.Path]::GetFullPath($PublishDir)
if (-not (Test-Path -LiteralPath $resolvedPublishDir)) {
throw "Publish directory not found: $resolvedPublishDir"
}
Write-Host "Optimizing publish payload for $RuntimeIdentifier..."
Remove-PdbFiles -Root $resolvedPublishDir
Remove-NonTargetRuntimeDirectories -Root $resolvedPublishDir -Rid $RuntimeIdentifier
Write-PayloadAudit -Root $resolvedPublishDir
if ($AssertClean) {
Assert-WindowsPayloadClean -Root $resolvedPublishDir -Rid $RuntimeIdentifier
}

View File

@@ -199,6 +199,60 @@ function Add-LinuxDesktopAssets {
Copy-Item -LiteralPath $installScriptSource -Destination (Join-Path $PublishedDirectory "install.sh") -Force Copy-Item -LiteralPath $installScriptSource -Destination (Join-Path $PublishedDirectory "install.sh") -Force
} }
function Invoke-PublishPayloadOptimization {
param(
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
[Parameter(Mandatory = $true)][string]$Rid
)
$optimizer = Join-Path $scriptRoot "Optimize-PublishPayload.ps1"
if (-not (Test-Path -LiteralPath $optimizer)) {
throw "Publish payload optimizer is missing: $optimizer"
}
& $optimizer `
-PublishDir $PublishedDirectory `
-RuntimeIdentifier $Rid `
-AssertClean `
-KeepSymbols:$KeepSymbols
if ($LASTEXITCODE -ne 0) {
throw "Publish payload optimization failed with exit code $LASTEXITCODE."
}
}
function Publish-AirAppHostPayload {
param(
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
[Parameter(Mandatory = $true)][string]$Rid,
[Parameter(Mandatory = $true)][string]$VersionValue
)
$airAppHostProject = Join-Path $repoRoot "..\LanMountainDesktop.AirAppHost\LanMountainDesktop.AirAppHost.csproj"
$airAppHostProject = Resolve-ExistingPath -PathValue $airAppHostProject
Write-Host "Publishing AirAppHost payload..."
$airPublishArgs = @(
"publish",
$airAppHostProject,
"-c", $Configuration,
"-r", $Rid,
"--self-contained", "false",
"-p:PublishSingleFile=false",
"-p:PublishTrimmed=false",
"-p:PublishReadyToRun=false",
"-p:DebugType=None",
"-p:DebugSymbols=false",
"-p:BuildingAirAppHost=true",
"-p:SkipAirAppHostBuild=true",
"-p:Version=$VersionValue",
"-o", $PublishedDirectory
)
& dotnet @airPublishArgs
if ($LASTEXITCODE -ne 0) {
throw "AirAppHost publish failed with exit code $LASTEXITCODE."
}
}
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path $scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Resolve-ExistingPath -PathValue (Join-Path $scriptRoot "..") $repoRoot = Resolve-ExistingPath -PathValue (Join-Path $scriptRoot "..")
@@ -231,6 +285,7 @@ $publishArgs = @(
"-p:PublishTrimmed=false", "-p:PublishTrimmed=false",
"-p:DebugType=None", "-p:DebugType=None",
"-p:DebugSymbols=false", "-p:DebugSymbols=false",
"-p:SkipAirAppHostBuild=true",
"-p:Version=$Version", "-p:Version=$Version",
"-o", $PublishDir "-o", $PublishDir
) )
@@ -240,6 +295,7 @@ if ($LASTEXITCODE -ne 0) {
throw "dotnet publish failed with exit code $LASTEXITCODE." throw "dotnet publish failed with exit code $LASTEXITCODE."
} }
Publish-AirAppHostPayload -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier -VersionValue $Version
Remove-LibVlcForOtherArch -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier Remove-LibVlcForOtherArch -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier
Remove-LegacyOutputArtifacts -TargetDirectory $PublishDir Remove-LegacyOutputArtifacts -TargetDirectory $PublishDir
@@ -247,11 +303,7 @@ if ($RuntimeIdentifier -like "linux-*") {
Add-LinuxDesktopAssets -PublishedDirectory $PublishDir -RepoRoot $repoRoot Add-LinuxDesktopAssets -PublishedDirectory $PublishDir -RepoRoot $repoRoot
} }
if (-not $KeepSymbols) { Invoke-PublishPayloadOptimization -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier
Get-ChildItem -Path $PublishDir -Recurse -File -Filter "*.pdb" | ForEach-Object {
[System.IO.File]::Delete($_.FullName)
}
}
if (Is-WindowsRuntimeIdentifier -Rid $RuntimeIdentifier) { if (Is-WindowsRuntimeIdentifier -Rid $RuntimeIdentifier) {
if (-not $InstallerOutputDir) { if (-not $InstallerOutputDir) {