Migrate to CliFx v3 (#1516)
Some checks failed
docker / pack (push) Has been cancelled
docker / deploy (push) Has been cancelled
main / format (push) Has been cancelled
main / test (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm64) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-musl-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-arm64) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-arm64) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x86) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm64) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-musl-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, osx-arm64) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, osx-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, win-arm64) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, win-x64) (push) Has been cancelled
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, win-x86) (push) Has been cancelled
main / release (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-musl-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-arm64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-arm64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x86) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-musl-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, osx-arm64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, osx-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, win-arm64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, win-x64) (push) Has been cancelled
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, win-x86) (push) Has been cancelled
main / notify (push) Has been cancelled

This commit is contained in:
Oleksii Holub 2026-03-26 23:53:28 +02:00 committed by GitHub
parent 661f82c478
commit cc703cc860
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 72 additions and 111 deletions

View file

@ -10,7 +10,7 @@
<PackageVersion Include="Avalonia" Version="11.3.12" /> <PackageVersion Include="Avalonia" Version="11.3.12" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.12" /> <PackageVersion Include="Avalonia.Desktop" Version="11.3.12" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" />
<PackageVersion Include="CliFx" Version="2.3.6" /> <PackageVersion Include="CliFx" Version="3.0.0-alpha.2" />
<PackageVersion Include="Cogwheel" Version="2.1.0" /> <PackageVersion Include="Cogwheel" Version="2.1.0" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" /> <PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="coverlet.collector" Version="8.0.0" /> <PackageVersion Include="coverlet.collector" Version="8.0.0" />
@ -26,7 +26,10 @@
<PackageVersion Include="Material.Avalonia" Version="3.9.2" /> <PackageVersion Include="Material.Avalonia" Version="3.9.2" />
<PackageVersion Include="Material.Icons.Avalonia" Version="2.2.0" /> <PackageVersion Include="Material.Icons.Avalonia" Version="2.2.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.3" /> <PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.3" /> <PackageVersion
Include="Microsoft.Extensions.Configuration.EnvironmentVariables"
Version="10.0.3"
/>
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.3" /> <PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" /> <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" /> <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />

View file

@ -2,7 +2,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Discord;
using DiscordChatExporter.Core.Utils; using DiscordChatExporter.Core.Utils;
@ -17,23 +17,22 @@ public abstract class DiscordCommandBase : ICommand
EnvironmentVariable = "DISCORD_TOKEN", EnvironmentVariable = "DISCORD_TOKEN",
Description = "Authentication token." Description = "Authentication token."
)] )]
public required string Token { get; init; } public required string Token { get; set; }
[Obsolete("This option doesn't do anything. Kept for backwards compatibility.")]
[CommandOption( [CommandOption(
"bot", "bot",
'b', 'b',
EnvironmentVariable = "DISCORD_TOKEN_BOT", EnvironmentVariable = "DISCORD_TOKEN_BOT",
Description = "This option doesn't do anything. Kept for backwards compatibility." Description = "This option doesn't do anything. Kept for backwards compatibility."
)] )]
public bool IsBotToken { get; init; } = false; public bool IsBotToken { get; set; } = false;
[CommandOption( [CommandOption(
"respect-rate-limits", "respect-rate-limits",
Description = "Whether to respect advisory rate limits. " Description = "Whether to respect advisory rate limits. "
+ "If disabled, only hard rate limits (i.e. 429 responses) will be respected." + "If disabled, only hard rate limits (i.e. 429 responses) will be respected."
)] )]
public bool ShouldRespectRateLimits { get; init; } = true; public bool ShouldRespectRateLimits { get; set; } = true;
[field: AllowNull, MaybeNull] [field: AllowNull, MaybeNull]
protected DiscordClient Discord => protected DiscordClient Discord =>

View file

@ -5,8 +5,8 @@ using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx;
using CliFx.Exceptions; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Converters; using DiscordChatExporter.Cli.Commands.Converters;
using DiscordChatExporter.Cli.Commands.Shared; using DiscordChatExporter.Cli.Commands.Shared;
@ -37,23 +37,23 @@ public abstract class ExportCommandBase : DiscordCommandBase
get; get;
// Handle ~/ in paths on Unix systems // Handle ~/ in paths on Unix systems
// https://github.com/Tyrrrz/DiscordChatExporter/pull/903 // https://github.com/Tyrrrz/DiscordChatExporter/pull/903
init => field = Path.GetFullPath(value); set => field = Path.GetFullPath(value);
} = Directory.GetCurrentDirectory(); } = Directory.GetCurrentDirectory();
[CommandOption("format", 'f', Description = "Export format.")] [CommandOption("format", 'f', Description = "Export format.")]
public ExportFormat ExportFormat { get; init; } = ExportFormat.HtmlDark; public ExportFormat ExportFormat { get; set; } = ExportFormat.HtmlDark;
[CommandOption( [CommandOption(
"after", "after",
Description = "Only include messages sent after this date or message ID." Description = "Only include messages sent after this date or message ID."
)] )]
public Snowflake? After { get; init; } public Snowflake? After { get; set; }
[CommandOption( [CommandOption(
"before", "before",
Description = "Only include messages sent before this date or message ID." Description = "Only include messages sent before this date or message ID."
)] )]
public Snowflake? Before { get; init; } public Snowflake? Before { get; set; }
[CommandOption( [CommandOption(
"partition", "partition",
@ -61,51 +61,51 @@ public abstract class ExportCommandBase : DiscordCommandBase
Description = "Split the output into partitions, each limited to the specified " Description = "Split the output into partitions, each limited to the specified "
+ "number of messages (e.g. '100') or file size (e.g. '10mb')." + "number of messages (e.g. '100') or file size (e.g. '10mb')."
)] )]
public PartitionLimit PartitionLimit { get; init; } = PartitionLimit.Null; public PartitionLimit PartitionLimit { get; set; } = PartitionLimit.Null;
[CommandOption( [CommandOption(
"include-threads", "include-threads",
Description = "Which types of threads should be included.", Description = "Which types of threads should be included.",
Converter = typeof(ThreadInclusionModeBindingConverter) Converter = typeof(ThreadInclusionModeInputConverter)
)] )]
public ThreadInclusionMode ThreadInclusionMode { get; init; } = ThreadInclusionMode.None; public ThreadInclusionMode ThreadInclusionMode { get; set; } = ThreadInclusionMode.None;
[CommandOption( [CommandOption(
"filter", "filter",
Description = "Only include messages that satisfy this filter. " Description = "Only include messages that satisfy this filter. "
+ "See the documentation for more info." + "See the documentation for more info."
)] )]
public MessageFilter MessageFilter { get; init; } = MessageFilter.Null; public MessageFilter MessageFilter { get; set; } = MessageFilter.Null;
[CommandOption( [CommandOption(
"parallel", "parallel",
Description = "Limits how many channels can be exported in parallel." Description = "Limits how many channels can be exported in parallel."
)] )]
public int ParallelLimit { get; init; } = 1; public int ParallelLimit { get; set; } = 1;
[CommandOption( [CommandOption(
"reverse", "reverse",
Description = "Export messages in reverse chronological order (newest first)." Description = "Export messages in reverse chronological order (newest first)."
)] )]
public bool IsReverseMessageOrder { get; init; } public bool IsReverseMessageOrder { get; set; }
[CommandOption( [CommandOption(
"markdown", "markdown",
Description = "Process markdown, mentions, and other special tokens." Description = "Process markdown, mentions, and other special tokens."
)] )]
public bool ShouldFormatMarkdown { get; init; } = true; public bool ShouldFormatMarkdown { get; set; } = true;
[CommandOption( [CommandOption(
"media", "media",
Description = "Download assets referenced by the export (user avatars, attached files, embedded images, etc.)." Description = "Download assets referenced by the export (user avatars, attached files, embedded images, etc.)."
)] )]
public bool ShouldDownloadAssets { get; init; } public bool ShouldDownloadAssets { get; set; }
[CommandOption( [CommandOption(
"reuse-media", "reuse-media",
Description = "Reuse previously downloaded assets to avoid redundant requests." Description = "Reuse previously downloaded assets to avoid redundant requests."
)] )]
public bool ShouldReuseAssets { get; init; } = false; public bool ShouldReuseAssets { get; set; } = false;
[CommandOption( [CommandOption(
"media-dir", "media-dir",
@ -117,34 +117,33 @@ public abstract class ExportCommandBase : DiscordCommandBase
get; get;
// Handle ~/ in paths on Unix systems // Handle ~/ in paths on Unix systems
// https://github.com/Tyrrrz/DiscordChatExporter/pull/903 // https://github.com/Tyrrrz/DiscordChatExporter/pull/903
init => field = value is not null ? Path.GetFullPath(value) : null; set => field = value is not null ? Path.GetFullPath(value) : null;
} }
[Obsolete("This option doesn't do anything. Kept for backwards compatibility.")]
[CommandOption( [CommandOption(
"dateformat", "dateformat",
Description = "This option doesn't do anything. Kept for backwards compatibility." Description = "This option doesn't do anything. Kept for backwards compatibility."
)] )]
public string DateFormat { get; init; } = "MM/dd/yyyy h:mm tt"; public string DateFormat { get; set; } = "MM/dd/yyyy h:mm tt";
[CommandOption( [CommandOption(
"locale", "locale",
Description = "Locale to use when formatting dates and numbers. " Description = "Locale to use when formatting dates and numbers. "
+ "If not specified, the default system locale will be used." + "If not specified, the default system locale will be used."
)] )]
public string? Locale { get; init; } public string? Locale { get; set; }
[CommandOption("utc", Description = "Normalize all timestamps to UTC+0.")] [CommandOption("utc", Description = "Normalize all timestamps to UTC+0.")]
public bool IsUtcNormalizationEnabled { get; init; } = false; public bool IsUtcNormalizationEnabled { get; set; } = false;
[CommandOption( [CommandOption(
"fuck-russia", "fuck-russia",
EnvironmentVariable = "FUCK_RUSSIA", EnvironmentVariable = "FUCK_RUSSIA",
Description = "Don't print the Support Ukraine message to the console.", Description = "Don't print the Support Ukraine message to the console.",
// Use a converter to accept '1' as 'true' to reuse the existing environment variable // Use a converter to accept '1' as 'true' to reuse the existing environment variable
Converter = typeof(TruthyBooleanBindingConverter) Converter = typeof(TruthyBooleanInputConverter)
)] )]
public bool IsUkraineSupportMessageDisabled { get; init; } = false; public bool IsUkraineSupportMessageDisabled { get; set; } = false;
[field: AllowNull, MaybeNull] [field: AllowNull, MaybeNull]
protected ChannelExporter Exporter => field ??= new ChannelExporter(Discord); protected ChannelExporter Exporter => field ??= new ChannelExporter(Discord);

View file

@ -1,10 +1,10 @@
using System; using System;
using CliFx.Extensibility; using CliFx.Activation;
using DiscordChatExporter.Cli.Commands.Shared; using DiscordChatExporter.Cli.Commands.Shared;
namespace DiscordChatExporter.Cli.Commands.Converters; namespace DiscordChatExporter.Cli.Commands.Converters;
internal class ThreadInclusionModeBindingConverter : BindingConverter<ThreadInclusionMode> internal class ThreadInclusionModeInputConverter : ScalarInputConverter<ThreadInclusionMode>
{ {
public override ThreadInclusionMode Convert(string? rawValue) public override ThreadInclusionMode Convert(string? rawValue)
{ {

View file

@ -1,9 +1,9 @@
using System.Globalization; using System.Globalization;
using CliFx.Extensibility; using CliFx.Activation;
namespace DiscordChatExporter.Cli.Commands.Converters; namespace DiscordChatExporter.Cli.Commands.Converters;
internal class TruthyBooleanBindingConverter : BindingConverter<bool> internal class TruthyBooleanInputConverter : ScalarInputConverter<bool>
{ {
public override bool Convert(string? rawValue) public override bool Convert(string? rawValue)
{ {

View file

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Cli.Utils.Extensions; using DiscordChatExporter.Cli.Utils.Extensions;
@ -14,23 +14,23 @@ using Spectre.Console;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("exportall", Description = "Exports all accessible channels.")] [Command("exportall", Description = "Exports all accessible channels.")]
public class ExportAllCommand : ExportCommandBase public partial class ExportAllCommand : ExportCommandBase
{ {
[CommandOption("include-dm", Description = "Include direct message channels.")] [CommandOption("include-dm", Description = "Include direct message channels.")]
public bool IncludeDirectChannels { get; init; } = true; public bool IncludeDirectChannels { get; set; } = true;
[CommandOption("include-guilds", Description = "Include server channels.")] [CommandOption("include-guilds", Description = "Include server channels.")]
public bool IncludeGuildChannels { get; init; } = true; public bool IncludeGuildChannels { get; set; } = true;
[CommandOption("include-vc", Description = "Include voice channels.")] [CommandOption("include-vc", Description = "Include voice channels.")]
public bool IncludeVoiceChannels { get; init; } = true; public bool IncludeVoiceChannels { get; set; } = true;
[CommandOption( [CommandOption(
"data-package", "data-package",
Description = "Path to the personal data package (ZIP file) requested from Discord. " Description = "Path to the personal data package (ZIP file) requested from Discord. "
+ "If provided, only channels referenced in the dump will be exported." + "If provided, only channels referenced in the dump will be exported."
)] )]
public string? DataPackageFilePath { get; init; } public string? DataPackageFilePath { get; set; }
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Discord;
@ -10,7 +10,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("export", Description = "Exports one or multiple channels.")] [Command("export", Description = "Exports one or multiple channels.")]
public class ExportChannelsCommand : ExportCommandBase public partial class ExportChannelsCommand : ExportCommandBase
{ {
// TODO: change this to plural (breaking change) // TODO: change this to plural (breaking change)
[CommandOption( [CommandOption(
@ -19,7 +19,7 @@ public class ExportChannelsCommand : ExportCommandBase
Description = "Channel ID(s). " Description = "Channel ID(s). "
+ "If provided with category ID(s), all channels inside those categories will be exported." + "If provided with category ID(s), all channels inside those categories will be exported."
)] )]
public required IReadOnlyList<Snowflake> ChannelIds { get; init; } public required IReadOnlyList<Snowflake> ChannelIds { get; set; }
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -1,5 +1,5 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Discord.Data;
@ -8,7 +8,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("exportdm", Description = "Exports all direct message channels.")] [Command("exportdm", Description = "Exports all direct message channels.")]
public class ExportDirectMessagesCommand : ExportCommandBase public partial class ExportDirectMessagesCommand : ExportCommandBase
{ {
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Cli.Utils.Extensions; using DiscordChatExporter.Cli.Utils.Extensions;
@ -11,13 +11,13 @@ using Spectre.Console;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("exportguild", Description = "Exports all channels within the specified server.")] [Command("exportguild", Description = "Exports all channels within the specified server.")]
public class ExportGuildCommand : ExportCommandBase public partial class ExportGuildCommand : ExportCommandBase
{ {
[CommandOption("guild", 'g', Description = "Server ID.")] [CommandOption("guild", 'g', Description = "Server ID.")]
public required Snowflake GuildId { get; init; } public required Snowflake GuildId { get; set; }
[CommandOption("include-vc", Description = "Include voice channels.")] [CommandOption("include-vc", Description = "Include voice channels.")]
public bool IncludeVoiceChannels { get; init; } = true; public bool IncludeVoiceChannels { get; set; } = true;
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Cli.Commands.Converters; using DiscordChatExporter.Cli.Commands.Converters;
@ -12,20 +12,20 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("channels", Description = "Get the list of channels in a server.")] [Command("channels", Description = "Get the list of channels in a server.")]
public class GetChannelsCommand : DiscordCommandBase public partial class GetChannelsCommand : DiscordCommandBase
{ {
[CommandOption("guild", 'g', Description = "Server ID.")] [CommandOption("guild", 'g', Description = "Server ID.")]
public required Snowflake GuildId { get; init; } public required Snowflake GuildId { get; set; }
[CommandOption("include-vc", Description = "Include voice channels.")] [CommandOption("include-vc", Description = "Include voice channels.")]
public bool IncludeVoiceChannels { get; init; } = true; public bool IncludeVoiceChannels { get; set; } = true;
[CommandOption( [CommandOption(
"include-threads", "include-threads",
Description = "Which types of threads should be included.", Description = "Which types of threads should be included.",
Converter = typeof(ThreadInclusionModeBindingConverter) Converter = typeof(ThreadInclusionModeInputConverter)
)] )]
public ThreadInclusionMode ThreadInclusionMode { get; init; } = ThreadInclusionMode.None; public ThreadInclusionMode ThreadInclusionMode { get; set; } = ThreadInclusionMode.None;
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Discord.Data;
@ -10,7 +10,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("dm", Description = "Gets the list of all direct message channels.")] [Command("dm", Description = "Gets the list of all direct message channels.")]
public class GetDirectChannelsCommand : DiscordCommandBase public partial class GetDirectChannelsCommand : DiscordCommandBase
{ {
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Base;
using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Discord.Data;
@ -10,7 +10,7 @@ using DiscordChatExporter.Core.Utils.Extensions;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("guilds", Description = "Gets the list of accessible servers.")] [Command("guilds", Description = "Gets the list of accessible servers.")]
public class GetGuildsCommand : DiscordCommandBase public partial class GetGuildsCommand : DiscordCommandBase
{ {
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -1,13 +1,13 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
namespace DiscordChatExporter.Cli.Commands; namespace DiscordChatExporter.Cli.Commands;
[Command("guide", Description = "Explains how to obtain the token, server or channel ID.")] [Command("guide", Description = "Explains how to obtain the token, server or channel ID.")]
public class GuideCommand : ICommand public partial class GuideCommand : ICommand
{ {
public ValueTask ExecuteAsync(IConsole console) public ValueTask ExecuteAsync(IConsole console)
{ {

View file

@ -6,12 +6,6 @@
<CopyOutputSymbolsToPublishDirectory>false</CopyOutputSymbolsToPublishDirectory> <CopyOutputSymbolsToPublishDirectory>false</CopyOutputSymbolsToPublishDirectory>
</PropertyGroup> </PropertyGroup>
<!-- HACK: Disable trim warnings because they seem to break when the code contains C# 14 extension blocks -->
<PropertyGroup>
<EnableTrimAnalyzer>false</EnableTrimAnalyzer>
<EnableAotAnalyzer>false</EnableAotAnalyzer>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CliFx" /> <PackageReference Include="CliFx" />
<PackageReference Include="CSharpier.MsBuild" PrivateAssets="all" /> <PackageReference Include="CSharpier.MsBuild" PrivateAssets="all" />

View file

@ -1,41 +1,13 @@
using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks;
using System.Threading.Tasks;
using CliFx; using CliFx;
using DiscordChatExporter.Cli.Commands;
using DiscordChatExporter.Cli.Commands.Converters;
using DiscordChatExporter.Core.Exporting.Filtering;
using DiscordChatExporter.Core.Exporting.Partitioning;
namespace DiscordChatExporter.Cli; namespace DiscordChatExporter.Cli;
public static class Program public static class Program
{ {
// Explicit references because CliFx relies on reflection and we're publishing with trimming enabled
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportAllCommand))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportChannelsCommand))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportDirectMessagesCommand))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ExportGuildCommand))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetChannelsCommand))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetDirectChannelsCommand))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GetGuildsCommand))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(GuideCommand))]
[DynamicDependency(
DynamicallyAccessedMemberTypes.All,
typeof(ThreadInclusionModeBindingConverter)
)]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(TruthyBooleanBindingConverter))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PartitionLimit))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(MessageFilter))]
public static async Task<int> Main(string[] args) => public static async Task<int> Main(string[] args) =>
await new CliApplicationBuilder() await new CommandLineApplicationBuilder()
.AddCommand<ExportAllCommand>() .AddCommandsFromThisAssembly()
.AddCommand<ExportChannelsCommand>()
.AddCommand<ExportDirectMessagesCommand>()
.AddCommand<ExportGuildCommand>()
.AddCommand<GetChannelsCommand>()
.AddCommand<GetDirectChannelsCommand>()
.AddCommand<GetGuildsCommand>()
.AddCommand<GuideCommand>()
.Build() .Build()
.RunAsync(args); .RunAsync(args);
} }

View file

@ -21,12 +21,6 @@
<PublishMacOSBundle>false</PublishMacOSBundle> <PublishMacOSBundle>false</PublishMacOSBundle>
</PropertyGroup> </PropertyGroup>
<!-- HACK: Disable trim warnings because they seem to break when the code contains C# 14 extension blocks -->
<PropertyGroup>
<EnableTrimAnalyzer>false</EnableTrimAnalyzer>
<EnableAotAnalyzer>false</EnableAotAnalyzer>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<AvaloniaResource Include="..\favicon.ico" Link="favicon.ico" /> <AvaloniaResource Include="..\favicon.ico" Link="favicon.ico" />
</ItemGroup> </ItemGroup>

View file

@ -2,16 +2,16 @@
#:package CliFx #:package CliFx
using CliFx; using CliFx;
using CliFx.Attributes; using CliFx.Binding;
using CliFx.Infrastructure; using CliFx.Infrastructure;
return await new CliApplicationBuilder() return await new CommandLineApplicationBuilder()
.AddCommand<PublishMacOSBundleCommand>() .AddCommandsFromThisAssembly()
.Build() .Build()
.RunAsync(args); .RunAsync(args);
[Command(Description = "Publishes the GUI app as a macOS .app bundle.")] [Command(Description = "Publishes the GUI app as a macOS .app bundle.")]
public class PublishMacOSBundleCommand : ICommand public partial class PublishMacOSBundleCommand : ICommand
{ {
private const string BundleName = "DiscordChatExporter.app"; private const string BundleName = "DiscordChatExporter.app";
private const string AppName = "DiscordChatExporter"; private const string AppName = "DiscordChatExporter";
@ -21,16 +21,16 @@ public class PublishMacOSBundleCommand : ICommand
private const string AppIconName = "AppIcon"; private const string AppIconName = "AppIcon";
[CommandOption("publish-dir", Description = "Path to the publish output directory.")] [CommandOption("publish-dir", Description = "Path to the publish output directory.")]
public required string PublishDirPath { get; init; } public required string PublishDirPath { get; set; }
[CommandOption("icons-file", Description = "Path to the .icns icons file.")] [CommandOption("icons-file", Description = "Path to the .icns icons file.")]
public required string IconsFilePath { get; init; } public required string IconsFilePath { get; set; }
[CommandOption("full-version", Description = "Full version string (e.g. '1.2.3.4').")] [CommandOption("full-version", Description = "Full version string (e.g. '1.2.3.4').")]
public required string FullVersion { get; init; } public required string FullVersion { get; set; }
[CommandOption("short-version", Description = "Short version string (e.g. '1.2.3').")] [CommandOption("short-version", Description = "Short version string (e.g. '1.2.3').")]
public required string ShortVersion { get; init; } public required string ShortVersion { get; set; }
public async ValueTask ExecuteAsync(IConsole console) public async ValueTask ExecuteAsync(IConsole console)
{ {