mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
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 Codepull/3404/head
9 changed files with 286 additions and 17 deletions
@ -0,0 +1,119 @@
@@ -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_<version>.zip Info-ZIP archive (preserves the execute flag, unlike |
||||
# Compress-Archive/7z, which drop unix mode bits) |
||||
# ilspy_<version>-1_amd64.deb built with dpkg-deb |
||||
# ilspy-<version>-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)" |
||||
@ -0,0 +1,63 @@
@@ -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_<version>.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" |
||||
@ -0,0 +1,12 @@
@@ -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 <https://github.com/icsharpcode> |
||||
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. |
||||
@ -0,0 +1,9 @@
@@ -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; |
||||
|
After Width: | Height: | Size: 39 KiB |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
# Built by BuildTools/package-linux.ps1, which stages the complete payload tree |
||||
# (/opt/ilspy + launcher symlink + desktop integration) and passes it in via |
||||
# rpmbuild -bb ilspy.spec --target x86_64 |
||||
# --define "_topdir <tmp>" --define "_version <version>" --define "_payload_dir <staged tree>" |
||||
|
||||
# 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 |
||||
Loading…
Reference in new issue