mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
feat.发布与打包优化
This commit is contained in:
58
.github/workflows/release.yml
vendored
58
.github/workflows/release.yml
vendored
@@ -179,6 +179,7 @@ jobs:
|
||||
-p:PublishSingleFile=false `
|
||||
-p:DebugType=none `
|
||||
-p:DebugSymbols=false `
|
||||
-p:SkipAirAppHostBuild=true `
|
||||
-p:PublishTrimmed=false `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:Version=${{ needs.prepare.outputs.version }} `
|
||||
@@ -193,6 +194,7 @@ jobs:
|
||||
-p:PublishSingleFile=false `
|
||||
-p:DebugType=none `
|
||||
-p:DebugSymbols=false `
|
||||
-p:SkipAirAppHostBuild=true `
|
||||
-p:PublishTrimmed=false `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:Version=${{ needs.prepare.outputs.version }} `
|
||||
@@ -202,6 +204,48 @@ jobs:
|
||||
}
|
||||
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
|
||||
run: |
|
||||
$version = "${{ needs.prepare.outputs.version }}"
|
||||
@@ -227,6 +271,18 @@ jobs:
|
||||
Move-Item -Path $newStructure -Destination $publishDir -Force
|
||||
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
|
||||
run: |
|
||||
choco install innosetup -y --no-progress
|
||||
@@ -418,6 +474,7 @@ jobs:
|
||||
-p:SelfContained=true \
|
||||
-p:DebugType=none \
|
||||
-p:DebugSymbols=false \
|
||||
-p:SkipAirAppHostBuild=true \
|
||||
-p:PublishTrimmed=false \
|
||||
-p:PublishReadyToRun=false \
|
||||
-p:Version=${{ needs.prepare.outputs.version }} \
|
||||
@@ -606,6 +663,7 @@ jobs:
|
||||
-p:SelfContained=true \
|
||||
-p:DebugType=none \
|
||||
-p:DebugSymbols=false \
|
||||
-p:SkipAirAppHostBuild=true \
|
||||
-p:PublishTrimmed=false \
|
||||
-p:PublishReadyToRun=false \
|
||||
-p:Version=${{ needs.prepare.outputs.version }} \
|
||||
|
||||
@@ -33,6 +33,8 @@ internal sealed class AirAppHostLocator
|
||||
{
|
||||
yield return Path.Combine(deploymentDirectory, "AirAppHost", WindowsExecutableName);
|
||||
yield return Path.Combine(deploymentDirectory, "AirAppHost", DllName);
|
||||
yield return Path.Combine(deploymentDirectory, WindowsExecutableName);
|
||||
yield return Path.Combine(deploymentDirectory, DllName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,9 +126,11 @@
|
||||
SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyAirAppHostPublishOutput" AfterTargets="Publish" Condition="'$(PublishDir)' != ''">
|
||||
<Target Name="CopyAirAppHostPublishOutput"
|
||||
AfterTargets="Publish"
|
||||
Condition="'$(PublishDir)' != '' and '$(AirAppHostPublishDir)' != '' and '$(SkipAirAppHostBuild)' != 'true'">
|
||||
<ItemGroup>
|
||||
<_AirAppHostPublishOutput Include="..\LanMountainDesktop.AirAppHost\bin\$(Configuration)\$(TargetFramework)\**\*" />
|
||||
<_AirAppHostPublishOutput Include="$(AirAppHostPublishDir)\**\*" />
|
||||
</ItemGroup>
|
||||
<MakeDir Directories="$(PublishDir)AirAppHost" />
|
||||
<Copy SourceFiles="@(_AirAppHostPublishOutput)"
|
||||
|
||||
203
LanMountainDesktop/scripts/Optimize-PublishPayload.ps1
Normal file
203
LanMountainDesktop/scripts/Optimize-PublishPayload.ps1
Normal 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
|
||||
}
|
||||
@@ -199,6 +199,60 @@ function Add-LinuxDesktopAssets {
|
||||
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
|
||||
$repoRoot = Resolve-ExistingPath -PathValue (Join-Path $scriptRoot "..")
|
||||
|
||||
@@ -231,6 +285,7 @@ $publishArgs = @(
|
||||
"-p:PublishTrimmed=false",
|
||||
"-p:DebugType=None",
|
||||
"-p:DebugSymbols=false",
|
||||
"-p:SkipAirAppHostBuild=true",
|
||||
"-p:Version=$Version",
|
||||
"-o", $PublishDir
|
||||
)
|
||||
@@ -240,6 +295,7 @@ if ($LASTEXITCODE -ne 0) {
|
||||
throw "dotnet publish failed with exit code $LASTEXITCODE."
|
||||
}
|
||||
|
||||
Publish-AirAppHostPayload -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier -VersionValue $Version
|
||||
Remove-LibVlcForOtherArch -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier
|
||||
Remove-LegacyOutputArtifacts -TargetDirectory $PublishDir
|
||||
|
||||
@@ -247,11 +303,7 @@ if ($RuntimeIdentifier -like "linux-*") {
|
||||
Add-LinuxDesktopAssets -PublishedDirectory $PublishDir -RepoRoot $repoRoot
|
||||
}
|
||||
|
||||
if (-not $KeepSymbols) {
|
||||
Get-ChildItem -Path $PublishDir -Recurse -File -Filter "*.pdb" | ForEach-Object {
|
||||
[System.IO.File]::Delete($_.FullName)
|
||||
}
|
||||
}
|
||||
Invoke-PublishPayloadOptimization -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier
|
||||
|
||||
if (Is-WindowsRuntimeIdentifier -Rid $RuntimeIdentifier) {
|
||||
if (-not $InstallerOutputDir) {
|
||||
|
||||
Reference in New Issue
Block a user