From b6b1bf99be06def101713e5623c6e867a3a62ee2 Mon Sep 17 00:00:00 2001 From: Christoph Wille Date: Thu, 11 Jun 2026 11:09:29 +0200 Subject: [PATCH] Add Linux and macOS publish and packaging scripts With the move to Avalonia the app runs on Linux and macOS, so the distribution tooling grows beyond Windows: publish.ps1 gains a -Platform parameter (the default keeps the Windows behavior unchanged), and new BuildTools scripts package the self-contained publish outputs into a zip, deb, and rpm on Linux and a zipped ILSpy.app on macOS. Nothing is signed at package time; signing happens offline on the release manager machine. Info-ZIP zip is used instead of Compress-Archive because the latter drops unix mode bits. deb/rpm are built with dpkg-deb/rpmbuild directly (both preinstalled on GitHub ubuntu runners) following sourcegit-scm/sourcegit's proven model, including the libicu OR-chain in the deb control file and disabled auto-requires for the self-contained rpm payload. Pre-release versions map '-' to '~' so both package managers sort them before the release. The macOS bundle's Info.plist now carries placeholders stamped at package time; on Windows the spec/control/desktop files are kept LF via .gitattributes because Linux tools consume them verbatim. Assisted-by: Claude:claude-fable-5:Claude Code --- .gitattributes | 5 + BuildTools/package-linux.ps1 | 119 ++++++++++++++++++ BuildTools/package-macos.ps1 | 63 ++++++++++ .../packaging/linux/deb/control.template | 12 ++ BuildTools/packaging/linux/ilspy.desktop | 9 ++ BuildTools/packaging/linux/ilspy.png | Bin 0 -> 40231 bytes BuildTools/packaging/linux/rpm/ilspy.spec | 36 ++++++ ILSpy/Assets/macos/Info.plist | 7 +- publish.ps1 | 52 +++++--- 9 files changed, 286 insertions(+), 17 deletions(-) create mode 100644 BuildTools/package-linux.ps1 create mode 100644 BuildTools/package-macos.ps1 create mode 100644 BuildTools/packaging/linux/deb/control.template create mode 100644 BuildTools/packaging/linux/ilspy.desktop create mode 100644 BuildTools/packaging/linux/ilspy.png create mode 100644 BuildTools/packaging/linux/rpm/ilspy.spec diff --git a/.gitattributes b/.gitattributes index 4945948f6..a6227fffc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,8 @@ *.cs text eol=crlf diff=csharp *.sln text eol=crlf *.csproj text eol=crlf +# Consumed verbatim by Linux tools (shell-executed rpm spec, dpkg control, desktop entry); +# CRLF breaks them, so keep them LF even in Windows working trees. +*.spec text eol=lf +*.desktop text eol=lf +control.template text eol=lf diff --git a/BuildTools/package-linux.ps1 b/BuildTools/package-linux.ps1 new file mode 100644 index 000000000..07409ba3a --- /dev/null +++ b/BuildTools/package-linux.ps1 @@ -0,0 +1,119 @@ +#!/usr/bin/env pwsh +# Package the linux-x64 self-contained publish output (created by `./publish.ps1 -Platform linux`) +# into the Linux distribution artifacts: +# ILSpy_linux-x64_.zip Info-ZIP archive (preserves the execute flag, unlike +# Compress-Archive/7z, which drop unix mode bits) +# ilspy_-1_amd64.deb built with dpkg-deb +# ilspy--1.x86_64.rpm built with rpmbuild +# Must run on Linux. zip and dpkg-deb are preinstalled on GitHub's ubuntu runners; +# locally: sudo apt-get install -y zip dpkg rpm +param( + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + # Defaults to the CI-computed version (env var, then the ILSPY_VERSION file written by + # BuildTools/ghactions-install.ps1), falling back to the committed VERSION file for + # local runs. + [string]$Version, + [string]$StagingDirectory = 'buildartifacts' +) +$ErrorActionPreference = 'Stop' +$PSNativeCommandUseErrorActionPreference = $true + +$repoRoot = Split-Path -Parent $PSScriptRoot +$resources = Join-Path $PSScriptRoot 'packaging/linux' + +foreach ($tool in 'zip', 'dpkg-deb', 'rpmbuild') { + if (-not (Get-Command $tool -ErrorAction SilentlyContinue)) { + throw "'$tool' not found. This script must run on Linux; install the tools with: sudo apt-get install -y zip dpkg rpm" + } +} + +if (-not $Version) { + if ($env:ILSPY_VERSION_NUMBER) { + $Version = $env:ILSPY_VERSION_NUMBER + } + elseif (Test-Path (Join-Path $repoRoot 'ILSPY_VERSION')) { + $Version = (Get-Content (Join-Path $repoRoot 'ILSPY_VERSION') -Raw).Trim() + } + else { + $Version = (Get-Content (Join-Path $repoRoot 'VERSION') -Raw).Trim() + } +} + +$publishDir = Join-Path $repoRoot "ILSpy/bin/$Configuration/net10.0/linux-x64/publish/selfcontained" +if (-not (Test-Path (Join-Path $publishDir 'ILSpy'))) { + throw "Publish output not found at $publishDir. Run ./publish.ps1 -Configuration $Configuration -Platform linux first." +} + +$staging = New-Item -ItemType Directory -Force (Join-Path $repoRoot $StagingDirectory) + +# ----- zip ----- +$zipPath = Join-Path $staging "ILSpy_linux-x64_$Version.zip" +Remove-Item $zipPath -ErrorAction Ignore +Push-Location $publishDir +try { + zip -r -q $zipPath . -x '*.pdb' +} +finally { + Pop-Location +} +Write-Host "created $zipPath" + +# Both dpkg and rpm reject '-' inside a version (it separates the package revision in deb +# and is illegal in the rpm Version tag). '~' is legal in both and sorts *before* the +# plain version, which is the correct semantic for pre-release suffixes like '-preview1'. +$pkgVersion = $Version -replace '-', '~' + +# Shared payload layout for both package formats: the app in /opt/ilspy, a launcher +# symlink on PATH, and desktop integration files. +function Copy-PackagePayload([string]$root) { + New-Item -ItemType Directory -Force (Join-Path $root 'opt/ilspy'), (Join-Path $root 'usr/bin'), + (Join-Path $root 'usr/share/applications'), (Join-Path $root 'usr/share/icons/hicolor/256x256/apps') | Out-Null + Copy-Item "$publishDir/*" (Join-Path $root 'opt/ilspy') -Recurse + Get-ChildItem (Join-Path $root 'opt/ilspy') -Filter '*.pdb' -Recurse | Remove-Item + chmod 755 (Join-Path $root 'opt/ilspy/ILSpy') + ln -s /opt/ilspy/ILSpy (Join-Path $root 'usr/bin/ilspy') + Copy-Item (Join-Path $resources 'ilspy.desktop') (Join-Path $root 'usr/share/applications') + Copy-Item (Join-Path $resources 'ilspy.png') (Join-Path $root 'usr/share/icons/hicolor/256x256/apps') + chmod 644 (Join-Path $root 'usr/share/applications/ilspy.desktop') (Join-Path $root 'usr/share/icons/hicolor/256x256/apps/ilspy.png') +} + +# ----- deb ----- +$debRoot = Join-Path ([IO.Path]::GetTempPath()) 'ilspy-deb' +Remove-Item -Recurse -Force $debRoot -ErrorAction Ignore +New-Item -ItemType Directory -Force (Join-Path $debRoot 'DEBIAN') | Out-Null +Copy-PackagePayload $debRoot + +# Debian has no unversioned libicu package and the soname-versioned name differs per +# release, so depend on an OR-chain covering the releases we care about (the leading +# plain 'libicu' catches derivatives that do ship a virtual package). +$icuVersions = 78, 77, 76, 74, 72, 71, 70, 69, 68, 67, 66, 65, 63 +$icuDeps = (@('libicu') + ($icuVersions | ForEach-Object { "libicu$_" })) -join ' | ' +$installedSize = [int]((Get-ChildItem $debRoot -Recurse -File | Measure-Object Length -Sum).Sum / 1024) + +$control = (Get-Content (Join-Path $resources 'deb/control.template') -Raw). + Replace('@VERSION@', "$pkgVersion-1"). + Replace('@ARCH@', 'amd64'). + Replace('@INSTALLED_SIZE@', "$installedSize"). + Replace('@ICU_DEPS@', $icuDeps) +Set-Content (Join-Path $debRoot 'DEBIAN/control') $control + +$debPath = Join-Path $staging "ilspy_${pkgVersion}-1_amd64.deb" +# gzip instead of dpkg's zstd default so the package installs on older dpkg versions +dpkg-deb -Zgzip --root-owner-group --build $debRoot $debPath +Write-Host "created $debPath" + +# ----- rpm ----- +$rpmTop = Join-Path ([IO.Path]::GetTempPath()) 'ilspy-rpm' +Remove-Item -Recurse -Force $rpmTop -ErrorAction Ignore +$rpmRoot = Join-Path $rpmTop 'payload' +New-Item -ItemType Directory -Force $rpmRoot | Out-Null +Copy-PackagePayload $rpmRoot + +rpmbuild -bb (Join-Path $resources 'rpm/ilspy.spec') --target x86_64 ` + --define "_topdir $rpmTop" ` + --define "_version $pkgVersion" ` + --define "_payload_dir $rpmRoot" +$rpm = Get-ChildItem (Join-Path $rpmTop 'RPMS') -Filter '*.rpm' -Recurse +Move-Item $rpm.FullName $staging -Force +Write-Host "created $(Join-Path $staging $rpm.Name)" diff --git a/BuildTools/package-macos.ps1 b/BuildTools/package-macos.ps1 new file mode 100644 index 000000000..aaf907e73 --- /dev/null +++ b/BuildTools/package-macos.ps1 @@ -0,0 +1,63 @@ +#!/usr/bin/env pwsh +# Package the osx-arm64 ILSpy.app bundle (created by `./publish.ps1 -Platform macos` via the +# BuildMacAppBundle target in ILSpy.csproj) into ILSpy_macos-arm64_.zip. +# Stamps the version placeholders in the bundle's Info.plist first. +# Must run on macOS/Linux: Info-ZIP's zip preserves the execute flag and (-y) symlinks, +# which Compress-Archive does not. +param( + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + # Defaults to the CI-computed version (env var, then the ILSPY_VERSION file written by + # BuildTools/ghactions-install.ps1), falling back to the committed VERSION file for + # local runs. + [string]$Version, + [string]$StagingDirectory = 'buildartifacts' +) +$ErrorActionPreference = 'Stop' +$PSNativeCommandUseErrorActionPreference = $true + +$repoRoot = Split-Path -Parent $PSScriptRoot + +if (-not (Get-Command zip -ErrorAction SilentlyContinue)) { + throw "'zip' not found. This script needs Info-ZIP, available on macOS and Linux." +} + +if (-not $Version) { + if ($env:ILSPY_VERSION_NUMBER) { + $Version = $env:ILSPY_VERSION_NUMBER + } + elseif (Test-Path (Join-Path $repoRoot 'ILSPY_VERSION')) { + $Version = (Get-Content (Join-Path $repoRoot 'ILSPY_VERSION') -Raw).Trim() + } + else { + $Version = (Get-Content (Join-Path $repoRoot 'VERSION') -Raw).Trim() + } +} + +$publishDir = Join-Path $repoRoot "ILSpy/bin/$Configuration/net10.0/osx-arm64/publish" +$appDir = Join-Path $publishDir 'ILSpy.app' +if (-not (Test-Path $appDir)) { + throw "ILSpy.app not found at $appDir. Run ./publish.ps1 -Configuration $Configuration -Platform macos first." +} + +# CFBundleVersion / CFBundleShortVersionString must be dotted numerics; strip the +# pre-release suffix (11.0.0.8948-preview1 -> 11.0.0.8948) and shorten to three parts. +$numericVersion = ($Version -split '-')[0] +$shortVersion = ($numericVersion -split '\.')[0..2] -join '.' +$plistPath = Join-Path $appDir 'Contents/Info.plist' +$plist = (Get-Content $plistPath -Raw). + Replace('ILSPY_SHORT_VERSION', $shortVersion). + Replace('ILSPY_VERSION', $numericVersion) +Set-Content $plistPath $plist + +$staging = New-Item -ItemType Directory -Force (Join-Path $repoRoot $StagingDirectory) +$zipPath = Join-Path $staging "ILSpy_macos-arm64_$Version.zip" +Remove-Item $zipPath -ErrorAction Ignore +Push-Location $publishDir +try { + zip -r -y -q $zipPath ILSpy.app -x '*.pdb' +} +finally { + Pop-Location +} +Write-Host "created $zipPath" diff --git a/BuildTools/packaging/linux/deb/control.template b/BuildTools/packaging/linux/deb/control.template new file mode 100644 index 000000000..56e8d9655 --- /dev/null +++ b/BuildTools/packaging/linux/deb/control.template @@ -0,0 +1,12 @@ +Package: ilspy +Version: @VERSION@ +Priority: optional +Section: devel +Architecture: @ARCH@ +Installed-Size: @INSTALLED_SIZE@ +Depends: libx11-6, libice6, libsm6, libfontconfig1, @ICU_DEPS@, xdg-utils +Maintainer: ICSharpCode Team +Homepage: https://github.com/icsharpcode/ILSpy +Description: .NET assembly browser and decompiler + ILSpy is the open-source .NET assembly browser and decompiler, + built on Avalonia and the ICSharpCode.Decompiler engine. diff --git a/BuildTools/packaging/linux/ilspy.desktop b/BuildTools/packaging/linux/ilspy.desktop new file mode 100644 index 000000000..ef15d5128 --- /dev/null +++ b/BuildTools/packaging/linux/ilspy.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=ILSpy +Comment=.NET assembly browser and decompiler +Exec=/opt/ilspy/ILSpy %F +Icon=ilspy +Terminal=false +Type=Application +Categories=Development; +MimeType=application/x-msdownload;application/vnd.microsoft.portable-executable; diff --git a/BuildTools/packaging/linux/ilspy.png b/BuildTools/packaging/linux/ilspy.png new file mode 100644 index 0000000000000000000000000000000000000000..0f746e9fa63d89a05872f9d4f000c637876483c9 GIT binary patch literal 40231 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 ppMZP<@(IW%AfJGI0>6h7_" --define "_version " --define "_payload_dir " + +# The payload is a prebuilt self-contained .NET publish; skip post-install processing +# (stripping the bundled native libraries breaks them) and debuginfo extraction. +%global __os_install_post %{nil} +%global debug_package %{nil} +%global _build_id_links none + +Name: ilspy +Version: %{_version} +Release: 1 +Summary: .NET assembly browser and decompiler +License: MIT +URL: https://github.com/icsharpcode/ILSpy +# The self-contained payload bundles its own .NET runtime; automatic dependency scanning +# would generate requires for every bundled shared object, so dependencies are listed +# manually instead. +AutoReqProv: no +Requires: libX11, libSM, libICE, fontconfig, libicu + +%description +ILSpy is the open-source .NET assembly browser and decompiler, +built on Avalonia and the ICSharpCode.Decompiler engine. + +%install +mkdir -p %{buildroot} +cp -a %{_payload_dir}/. %{buildroot}/ + +%files +/opt/ilspy +/usr/bin/ilspy +/usr/share/applications/ilspy.desktop +/usr/share/icons/hicolor/256x256/apps/ilspy.png diff --git a/ILSpy/Assets/macos/Info.plist b/ILSpy/Assets/macos/Info.plist index ec4f16566..37b4a269c 100644 --- a/ILSpy/Assets/macos/Info.plist +++ b/ILSpy/Assets/macos/Info.plist @@ -8,10 +8,13 @@ ILSpy CFBundleIdentifier net.sharpdevelop.ilspy + CFBundleVersion - 10.1.0 + ILSPY_VERSION CFBundleShortVersionString - 10.1 + ILSPY_SHORT_VERSION CFBundlePackageType APPL CFBundleSignature diff --git a/publish.ps1 b/publish.ps1 index 873cebd27..a885ee196 100644 --- a/publish.ps1 +++ b/publish.ps1 @@ -1,26 +1,48 @@ #!/usr/bin/env pwsh -# Publish the Windows distribution bundles. Invoked by the build workflow as: -# .\publish.ps1 --configuration -# The win-x64 framework-dependent bundle is produced for every configuration (the binaries zip). -# The win-arm64 framework-dependent and win-x64 self-contained bundles are Release-only. +# Publish the per-platform distribution bundles. Invoked by the build workflow as: +# ./publish.ps1 -Configuration -Platform +# windows: win-x64 framework-dependent bundle for every configuration (the binaries zip); +# the win-arm64 framework-dependent and win-x64 self-contained bundles are Release-only. +# linux: linux-x64 self-contained bundle. +# macos: osx-arm64 self-contained bundle; the BuildMacAppBundle target in ILSpy.csproj +# assembles ILSpy.app next to the publish directory. param( [ValidateSet('Debug', 'Release')] - [string]$Configuration = 'Release' + [string]$Configuration = 'Release', + [ValidateSet('windows', 'linux', 'macos')] + [string]$Platform = 'windows' ) $ErrorActionPreference = 'Stop' $base = "./ILSpy/bin/$Configuration/net10.0" -$output_x64 = "$base/win-x64/publish/fwdependent" -dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --no-self-contained -r win-x64 -o $output_x64 -dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --no-self-contained -r win-x64 -o $output_x64 +switch ($Platform) { + 'windows' { + $output_x64 = "$base/win-x64/publish/fwdependent" + dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --no-self-contained -r win-x64 -o $output_x64 + dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --no-self-contained -r win-x64 -o $output_x64 -if ($Configuration -eq 'Release') { - $output_arm64 = "$base/win-arm64/publish/fwdependent" - dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --no-self-contained -r win-arm64 -o $output_arm64 - dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --no-self-contained -r win-arm64 -o $output_arm64 + if ($Configuration -eq 'Release') { + $output_arm64 = "$base/win-arm64/publish/fwdependent" + dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --no-self-contained -r win-arm64 -o $output_arm64 + dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --no-self-contained -r win-arm64 -o $output_arm64 - $output_x64_selfcontained = "$base/win-x64/publish/selfcontained" - dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --self-contained -r win-x64 -o $output_x64_selfcontained - dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --self-contained -r win-x64 -o $output_x64_selfcontained + $output_x64_selfcontained = "$base/win-x64/publish/selfcontained" + dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --self-contained -r win-x64 -o $output_x64_selfcontained + dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --self-contained -r win-x64 -o $output_x64_selfcontained + } + } + 'linux' { + $output = "$base/linux-x64/publish/selfcontained" + dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --self-contained -r linux-x64 -o $output + dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --self-contained -r linux-x64 -o $output + } + 'macos' { + $output = "$base/osx-arm64/publish/selfcontained" + # The ReadyToRun plugin must be published first: BuildMacAppBundle runs after the + # ILSpy publish and snapshots the publish directory into ILSpy.app/Contents/MacOS, + # so everything that belongs in the bundle has to be in place by then. + dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c $Configuration --no-restore --self-contained -r osx-arm64 -o $output + dotnet publish ./ILSpy/ILSpy.csproj -c $Configuration --no-restore --self-contained -r osx-arm64 -o $output + } }