From e794d7c8335127a824dcec0b3ed3cefeb1804ca6 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Mon, 23 Mar 2026 23:18:46 +0200
Subject: [PATCH] Replace `Publish-MacOSBundle.ps1` with a .NET 10 single-file
C# script (#1515)
Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
---
.../DiscordChatExporter.Gui.csproj | 2 +-
.../Publish-MacOSBundle.csx | 128 ++++++++++++++++++
.../Publish-MacOSBundle.ps1 | 87 ------------
3 files changed, 129 insertions(+), 88 deletions(-)
create mode 100644 DiscordChatExporter.Gui/Publish-MacOSBundle.csx
delete mode 100644 DiscordChatExporter.Gui/Publish-MacOSBundle.ps1
diff --git a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj
index e5e27df3..73ed4d1d 100644
--- a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj
+++ b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj
@@ -56,7 +56,7 @@
diff --git a/DiscordChatExporter.Gui/Publish-MacOSBundle.csx b/DiscordChatExporter.Gui/Publish-MacOSBundle.csx
new file mode 100644
index 00000000..ab6fc635
--- /dev/null
+++ b/DiscordChatExporter.Gui/Publish-MacOSBundle.csx
@@ -0,0 +1,128 @@
+#!/usr/bin/env -S dotnet run --
+#:package CliFx
+
+using CliFx;
+using CliFx.Attributes;
+using CliFx.Infrastructure;
+
+return await new CliApplicationBuilder()
+ .AddCommand()
+ .Build()
+ .RunAsync(args);
+
+[Command(Description = "Publishes the GUI app as a macOS .app bundle.")]
+public class PublishMacOSBundleCommand : ICommand
+{
+ private const string BundleName = "DiscordChatExporter.app";
+ private const string AppName = "DiscordChatExporter";
+ private const string AppCopyright = "© Oleksii Holub";
+ private const string AppIdentifier = "me.Tyrrrz.DiscordChatExporter";
+ private const string AppSpokenName = "Discord Chat Exporter";
+ private const string AppIconName = "AppIcon";
+
+ [CommandOption("publish-dir", Description = "Path to the publish output directory.")]
+ public required string PublishDirPath { get; init; }
+
+ [CommandOption("icons-file", Description = "Path to the .icns icons file.")]
+ public required string IconsFilePath { get; init; }
+
+ [CommandOption("full-version", Description = "Full version string (e.g. '1.2.3.4').")]
+ public required string FullVersion { get; init; }
+
+ [CommandOption("short-version", Description = "Short version string (e.g. '1.2.3').")]
+ public required string ShortVersion { get; init; }
+
+ public async ValueTask ExecuteAsync(IConsole console)
+ {
+ // Set up paths
+ var publishDirPath = Path.GetFullPath(PublishDirPath);
+ var tempDirPath = Path.GetFullPath(
+ Path.Combine(publishDirPath, "../publish-macos-app-temp")
+ );
+
+ // Ensure the temporary directory is clean before use in case a previous run crashed
+ if (Directory.Exists(tempDirPath))
+ Directory.Delete(tempDirPath, true);
+
+ var bundleDirPath = Path.Combine(tempDirPath, BundleName);
+ var contentsDirPath = Path.Combine(bundleDirPath, "Contents");
+
+ try
+ {
+ // Copy icons into the .app's Resources folder
+ Directory.CreateDirectory(Path.Combine(contentsDirPath, "Resources"));
+ File.Copy(
+ IconsFilePath,
+ Path.Combine(contentsDirPath, "Resources", "AppIcon.icns"),
+ true
+ );
+
+ // Generate the Info.plist metadata file with the app information
+ // lang=xml
+ var plistContent = $"""
+
+
+
+
+ CFBundleDisplayName
+ {AppName}
+ CFBundleName
+ {AppName}
+ CFBundleExecutable
+ {AppName}
+ NSHumanReadableCopyright
+ {AppCopyright}
+ CFBundleIdentifier
+ {AppIdentifier}
+ CFBundleSpokenName
+ {AppSpokenName}
+ CFBundleIconFile
+ {AppIconName}
+ CFBundleIconName
+ {AppIconName}
+ CFBundleVersion
+ {FullVersion}
+ CFBundleShortVersionString
+ {ShortVersion}
+ NSHighResolutionCapable
+
+ CFBundlePackageType
+ APPL
+
+
+ """;
+
+ await File.WriteAllTextAsync(Path.Combine(contentsDirPath, "Info.plist"), plistContent);
+
+ // Delete the previous bundle if it exists
+ var existingBundlePath = Path.Combine(publishDirPath, BundleName);
+ if (Directory.Exists(existingBundlePath))
+ Directory.Delete(existingBundlePath, true);
+
+ // Move all files from the publish directory into the MacOS directory
+ Directory.CreateDirectory(Path.Combine(contentsDirPath, "MacOS"));
+ foreach (var entryPath in Directory.GetFileSystemEntries(publishDirPath))
+ {
+ var destinationPath = Path.Combine(
+ contentsDirPath,
+ "MacOS",
+ Path.GetFileName(entryPath)
+ );
+
+ if (Directory.Exists(entryPath))
+ Directory.Move(entryPath, destinationPath);
+ else
+ File.Move(entryPath, destinationPath);
+ }
+
+ // Move the final bundle into the publish directory for upload
+ Directory.Move(bundleDirPath, Path.Combine(publishDirPath, BundleName));
+ }
+ finally
+ {
+ // Clean up the temporary directory
+ if (Directory.Exists(tempDirPath))
+ Directory.Delete(tempDirPath, true);
+ }
+ }
+}
diff --git a/DiscordChatExporter.Gui/Publish-MacOSBundle.ps1 b/DiscordChatExporter.Gui/Publish-MacOSBundle.ps1
deleted file mode 100644
index fd08ea22..00000000
--- a/DiscordChatExporter.Gui/Publish-MacOSBundle.ps1
+++ /dev/null
@@ -1,87 +0,0 @@
-param(
- [Parameter(Mandatory=$true)]
- [string]$PublishDirPath,
-
- [Parameter(Mandatory=$true)]
- [string]$IconsFilePath,
-
- [Parameter(Mandatory=$true)]
- [string]$FullVersion,
-
- [Parameter(Mandatory=$true)]
- [string]$ShortVersion
-)
-
-$ErrorActionPreference = "Stop"
-
-# Setup paths
-$tempDirPath = Join-Path $PublishDirPath "../publish-macos-app-temp"
-$bundleName = "DiscordChatExporter.app"
-$bundleDirPath = Join-Path $tempDirPath $bundleName
-$contentsDirPath = Join-Path $bundleDirPath "Contents"
-$macosDirPath = Join-Path $contentsDirPath "MacOS"
-$resourcesDirPath = Join-Path $contentsDirPath "Resources"
-
-try {
- # Initialize the bundle's directory structure
- New-Item -Path $bundleDirPath -ItemType Directory -Force
- New-Item -Path $contentsDirPath -ItemType Directory -Force
- New-Item -Path $macosDirPath -ItemType Directory -Force
- New-Item -Path $resourcesDirPath -ItemType Directory -Force
-
- # Copy icons into the .app's Resources folder
- Copy-Item -Path $IconsFilePath -Destination (Join-Path $resourcesDirPath "AppIcon.icns") -Force
-
- # Generate the Info.plist metadata file with the app information
- $plistContent = @"
-
-
-
-
- CFBundleDisplayName
- DiscordChatExporter
- CFBundleName
- DiscordChatExporter
- CFBundleExecutable
- DiscordChatExporter
- NSHumanReadableCopyright
- © Oleksii Holub
- CFBundleIdentifier
- me.Tyrrrz.DiscordChatExporter
- CFBundleSpokenName
- Discord Chat Exporter
- CFBundleIconFile
- AppIcon
- CFBundleIconName
- AppIcon
- CFBundleVersion
- $FullVersion
- CFBundleShortVersionString
- $ShortVersion
- NSHighResolutionCapable
-
- CFBundlePackageType
- APPL
-
-
-"@
-
- Set-Content -Path (Join-Path $contentsDirPath "Info.plist") -Value $plistContent
-
- # Delete the previous bundle if it exists
- if (Test-Path (Join-Path $PublishDirPath $bundleName)) {
- Remove-Item -Path (Join-Path $PublishDirPath $bundleName) -Recurse -Force
- }
-
- # Move all files from the publish directory into the MacOS directory
- Get-ChildItem -Path $PublishDirPath | ForEach-Object {
- Move-Item -Path $_.FullName -Destination $macosDirPath -Force
- }
-
- # Move the final bundle into the publish directory for upload
- Move-Item -Path $bundleDirPath -Destination $PublishDirPath -Force
-}
-finally {
- # Clean up the temporary directory
- Remove-Item -Path $tempDirPath -Recurse -Force
-}
\ No newline at end of file