From 12ce5fda0f4d0bfb36368554ee623298f598f6bf Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 24 Jul 2023 23:44:33 -0400 Subject: [PATCH 1/2] Set executable permissions for linux updater --- StabilityMatrix.Avalonia/Program.cs | 7 +++++++ .../ViewModels/Dialogs/UpdateViewModel.cs | 7 +++++++ StabilityMatrix.Core/Updater/UpdateHelper.cs | 13 +++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs index da0bcaca..314ef447 100644 --- a/StabilityMatrix.Avalonia/Program.cs +++ b/StabilityMatrix.Avalonia/Program.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; @@ -89,6 +90,12 @@ public class Program { currentExe.CopyTo(targetExe, true); + // Ensure permissions are set for unix + if (Compat.IsUnix) + { + File.SetUnixFileMode(targetExe, (UnixFileMode) 0x755); + } + // Start the new app Process.Start(targetExe); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs index 667903d0..611bd969 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/UpdateViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.IO; using System.Net.Http; using System.Threading.Tasks; using AsyncAwaitBestPractices; @@ -78,6 +79,12 @@ public partial class UpdateViewModel : ContentDialogViewModelBase ProgressValue = Convert.ToInt32(report.Percentage); })); + // On unix, we need to set the executable bit + if (Compat.IsUnix) + { + File.SetUnixFileMode(UpdateHelper.ExecutablePath, (UnixFileMode) 0x755); + } + UpdateText = "Update complete. Restarting Stability Matrix in 3 seconds..."; await Task.Delay(1000); UpdateText = "Update complete. Restarting Stability Matrix in 2 seconds..."; diff --git a/StabilityMatrix.Core/Updater/UpdateHelper.cs b/StabilityMatrix.Core/Updater/UpdateHelper.cs index 6026c3fc..4ade4d61 100644 --- a/StabilityMatrix.Core/Updater/UpdateHelper.cs +++ b/StabilityMatrix.Core/Updater/UpdateHelper.cs @@ -35,14 +35,14 @@ public class UpdateHelper : IUpdateHelper this.downloadService = downloadService; this.debugOptions = debugOptions.Value; - timer.Elapsed += async (_, _) => { await CheckForUpdate(); }; + timer.Elapsed += async (_, _) => { await CheckForUpdate().ConfigureAwait(false); }; } public async Task StartCheckingForUpdates() { timer.Enabled = true; timer.Start(); - await CheckForUpdate(); + await CheckForUpdate().ConfigureAwait(false); } public async Task DownloadUpdate(UpdateInfo updateInfo, @@ -54,7 +54,7 @@ public class UpdateHelper : IUpdateHelper // download the file from URL await downloadService.DownloadToFileAsync(downloadUrl, ExecutablePath, progress: progress, - httpClientName: "UpdateClient"); + httpClientName: "UpdateClient").ConfigureAwait(false); } @@ -77,17 +77,18 @@ public class UpdateHelper : IUpdateHelper try { var httpClient = httpClientFactory.CreateClient("UpdateClient"); - var response = await httpClient.GetAsync(UpdateManifestUrl); + var response = await httpClient.GetAsync(UpdateManifestUrl).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { logger.LogWarning("Error while checking for update {StatusCode} - {Content}", - response.StatusCode, await response.Content.ReadAsStringAsync()); + response.StatusCode, await response.Content.ReadAsStringAsync().ConfigureAwait(false)); return; } var updateCollection = await JsonSerializer.DeserializeAsync( - await response.Content.ReadAsStreamAsync()); + await response.Content.ReadAsStreamAsync() + .ConfigureAwait(false)).ConfigureAwait(false); if (updateCollection is null) { From 9d484efc0ce497b7b7f3ac690668d234d8afb747 Mon Sep 17 00:00:00 2001 From: Ionite Date: Mon, 24 Jul 2023 23:45:00 -0400 Subject: [PATCH 2/2] Organize launch arguments to Program.AppArgs --- StabilityMatrix.Avalonia/App.axaml.cs | 7 ++++++ StabilityMatrix.Avalonia/Models/AppArgs.cs | 28 ++++++++++++++++++++++ StabilityMatrix.Avalonia/Program.cs | 13 ++++++---- 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Models/AppArgs.cs diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index b9eef0a7..455163bd 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -13,6 +13,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; +using Avalonia.Platform; using Avalonia.Platform.Storage; using Avalonia.Styling; using FluentAvalonia.UI.Controls; @@ -107,6 +108,9 @@ public sealed class App : Application setupWindow.ShowAsDialog = true; setupWindow.ShowActivated = true; setupWindow.ShowAsyncCts = new CancellationTokenSource(); + + setupWindow.ExtendClientAreaChromeHints = Program.Args.NoWindowChromeEffects ? + ExtendClientAreaChromeHints.NoChrome : ExtendClientAreaChromeHints.PreferSystemChrome; DesktopLifetime.MainWindow = setupWindow; @@ -141,6 +145,9 @@ public sealed class App : Application var mainWindow = Services.GetRequiredService(); mainWindow.DataContext = mainViewModel; mainWindow.NotificationService = notificationService; + + mainWindow.ExtendClientAreaChromeHints = Program.Args.NoWindowChromeEffects ? + ExtendClientAreaChromeHints.NoChrome : ExtendClientAreaChromeHints.PreferSystemChrome; var settingsManager = Services.GetRequiredService(); var windowSettings = settingsManager.Settings.WindowSettings; diff --git a/StabilityMatrix.Avalonia/Models/AppArgs.cs b/StabilityMatrix.Avalonia/Models/AppArgs.cs new file mode 100644 index 00000000..ead4cce4 --- /dev/null +++ b/StabilityMatrix.Avalonia/Models/AppArgs.cs @@ -0,0 +1,28 @@ +namespace StabilityMatrix.Avalonia.Models; + +/// +/// Command line arguments passed to the application. +/// +public class AppArgs +{ + /// + /// Whether to use the exception dialog while debugger is attached. + /// When no debugger is attached, the exception dialog is always used. + /// + public bool DebugExceptionDialog { get; set; } + + /// + /// Whether to use Sentry when a debugger is attached. + /// + public bool DebugSentry { get; set; } + + /// + /// Whether to disable Sentry. + /// + public bool NoSentry { get; set; } + + /// + /// Whether to disable window chrome effects + /// + public bool NoWindowChromeEffects { get; set; } +} diff --git a/StabilityMatrix.Avalonia/Program.cs b/StabilityMatrix.Avalonia/Program.cs index 314ef447..0cc3df63 100644 --- a/StabilityMatrix.Avalonia/Program.cs +++ b/StabilityMatrix.Avalonia/Program.cs @@ -17,6 +17,7 @@ using Projektanker.Icons.Avalonia; using Projektanker.Icons.Avalonia.FontAwesome; using Semver; using Sentry; +using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels.Dialogs; using StabilityMatrix.Avalonia.Views.Dialogs; using StabilityMatrix.Core.Helper; @@ -28,7 +29,7 @@ namespace StabilityMatrix.Avalonia; [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public class Program { - private static bool isExceptionDialogEnabled; + public static AppArgs Args { get; } = new(); // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized @@ -36,6 +37,11 @@ public class Program [STAThread] public static void Main(string[] args) { + Args.DebugExceptionDialog = args.Contains("--debug-exception-dialog"); + Args.DebugSentry = args.Contains("--debug-sentry"); + Args.NoSentry = args.Contains("--no-sentry"); + Args.NoWindowChromeEffects = args.Contains("--no-window-chrome-effects"); + HandleUpdateReplacement(); var infoVersion = Assembly.GetExecutingAssembly() @@ -43,14 +49,13 @@ public class Program Compat.AppVersion = SemVersion.Parse(infoVersion ?? "0.0.0", SemVersionStyles.Strict); // Configure exception dialog for unhandled exceptions - if (!Debugger.IsAttached || args.Contains("--debug-exception-dialog")) + if (!Debugger.IsAttached || Args.DebugExceptionDialog) { - isExceptionDialogEnabled = true; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; } // Configure Sentry - if ((Debugger.IsAttached && args.Contains("--debug-sentry")) || !args.Contains("--no-sentry")) + if (!Args.NoSentry && (!Debugger.IsAttached || Args.DebugSentry)) { ConfigureSentry(); }