Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 31 additions & 25 deletions WheelWizard/Features/AutoUpdating/AutoUpdaterSingletonService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace WheelWizard.AutoUpdating;

public interface IAutoUpdaterSingletonService
{
public Task CheckForUpdatesAsync();
public Task CheckForUpdatesAsync(bool updateAutomatically = false);
}

public class AutoUpdaterSingletonService(
Expand All @@ -22,10 +22,10 @@ IGitHubSingletonService gitHubService
{
private string CurrentVersion => brandingService.Branding.Version;

public async Task CheckForUpdatesAsync()
public async Task CheckForUpdatesAsync(bool updateAutomatically = false)
{
// TODO: How to run this in a background thread?
var latestRelease = await GetLatestReleaseAsync();
var latestRelease = await GetLatestReleaseAsync(showErrors: !updateAutomatically);
if (latestRelease?.TagName is null)
return;

Expand All @@ -36,22 +36,25 @@ public async Task CheckForUpdatesAsync()
var latestVersion = SemVersion.Parse(latestRelease.TagName.TrimStart('v'), SemVersionStyles.Any);
var popupExtraText = t("question.new_version_wh_wz.extra", latestVersion, CurrentVersion)!;

var shouldUpdate = false;
await Dispatcher.UIThread.InvokeAsync(async () =>
var shouldUpdate = updateAutomatically;
if (!updateAutomatically)
{
shouldUpdate = await new YesNoWindow()
.SetButtonText(t("action.update"), t("action.maybe_later"))
.SetMainText(t("question.new_version_wh_wz.title"))
.SetExtraText(popupExtraText)
.AwaitAnswer();
});
await Dispatcher.UIThread.InvokeAsync(async () =>
{
shouldUpdate = await new YesNoWindow()
.SetButtonText(t("action.update"), t("action.maybe_later"))
.SetMainText(t("question.new_version_wh_wz.title"))
.SetExtraText(popupExtraText)
.AwaitAnswer();
});
}

if (!shouldUpdate)
return;

var updateResult = await updatePlatform.ExecuteUpdateAsync(asset.BrowserDownloadUrl);
var updateResult = await updatePlatform.ExecuteUpdateAsync(asset.BrowserDownloadUrl, restartApplication: !updateAutomatically);

if (updateResult.IsFailure)
if (updateResult.IsFailure && !updateAutomatically)
{
await new MessageBoxWindow()
.SetMessageType(MessageBoxWindow.MessageType.Warning)
Expand All @@ -61,23 +64,26 @@ await Dispatcher.UIThread.InvokeAsync(async () =>
}
}

private async Task<GithubRelease?> GetLatestReleaseAsync()
private async Task<GithubRelease?> GetLatestReleaseAsync(bool showErrors)
{
var releasesResult = await gitHubService.GetReleasesAsync();
if (releasesResult.IsFailure)
{
await Dispatcher.UIThread.InvokeAsync(async () =>
if (showErrors)
{
await new MessageBoxWindow()
.SetMessageType(MessageBoxWindow.MessageType.Error)
.SetTitleText("Failed to check for updates")
.SetInfoText(
"An error occurred while checking for updates. Please try again later. "
+ "\nError: "
+ releasesResult.Error.Message
)
.ShowDialog();
});
await Dispatcher.UIThread.InvokeAsync(async () =>
{
await new MessageBoxWindow()
.SetMessageType(MessageBoxWindow.MessageType.Error)
.SetTitleText("Failed to check for updates")
.SetInfoText(
"An error occurred while checking for updates. Please try again later. "
+ "\nError: "
+ releasesResult.Error.Message
)
.ShowDialog();
});
}

return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ public class FallbackUpdatePlatform(IBrandingSingletonService brandingService) :
return null;
}

public Task<OperationResult> ExecuteUpdateAsync(string downloadUrl) => Task.FromResult(Ok());
public Task<OperationResult> ExecuteUpdateAsync(string downloadUrl, bool restartApplication = true) => Task.FromResult(Ok());
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ public interface IUpdatePlatform
/// <summary>
/// Executes the update logic for the current platform.
/// </summary>
Task<OperationResult> ExecuteUpdateAsync(string downloadUrl);
Task<OperationResult> ExecuteUpdateAsync(string downloadUrl, bool restartApplication = true);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class LinuxUpdatePlatform(IFileSystem fileSystem) : IUpdatePlatform
return release.Assets.FirstOrDefault(asset => asset.BrowserDownloadUrl.Contains(identifier, StringComparison.OrdinalIgnoreCase));
}

public async Task<OperationResult> ExecuteUpdateAsync(string downloadUrl)
public async Task<OperationResult> ExecuteUpdateAsync(string downloadUrl, bool restartApplication = true)
{
var currentExecutablePath = Environment.ProcessPath;
if (currentExecutablePath is null)
Expand Down Expand Up @@ -55,7 +55,7 @@ public async Task<OperationResult> ExecuteUpdateAsync(string downloadUrl)
await Task.Delay(201);

// Create and run the shell script to perform the update.
var scriptResult = CreateAndRunShellScript(currentExecutablePath, newFilePath);
var scriptResult = CreateAndRunShellScript(currentExecutablePath, newFilePath, restartApplication);
if (scriptResult.IsFailure)
return scriptResult;

Expand All @@ -64,7 +64,7 @@ public async Task<OperationResult> ExecuteUpdateAsync(string downloadUrl)
return Ok();
}

private OperationResult CreateAndRunShellScript(string currentFilePath, string newFilePath)
private OperationResult CreateAndRunShellScript(string currentFilePath, string newFilePath, bool restartApplication)
{
var currentFolder = fileSystem.Path.GetDirectoryName(currentFilePath);
if (currentFolder is null)
Expand All @@ -74,6 +74,10 @@ private OperationResult CreateAndRunShellScript(string currentFilePath, string n
var originalFileName = fileSystem.Path.GetFileName(currentFilePath);
var newFileName = fileSystem.Path.GetFileName(newFilePath);

var restartCommand = restartApplication
? $"nohup {EnvHelper.SingleQuotePath(fileSystem.Path.Combine(currentFolder, originalFileName))} > /dev/null 2>&1 &"
: string.Empty;

var scriptContent = $"""
#!/usr/bin/env sh
echo 'Starting update process...'
Expand All @@ -89,7 +93,7 @@ sleep 1
chmod +x {EnvHelper.SingleQuotePath(fileSystem.Path.Combine(currentFolder, originalFileName))}

echo 'Starting the updated application...'
nohup {EnvHelper.SingleQuotePath(fileSystem.Path.Combine(currentFolder, originalFileName))} > /dev/null 2>&1 &
{restartCommand}

echo 'Cleaning up...'
rm -- {EnvHelper.SingleQuotePath(scriptFilePath)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ public class WindowsUpdatePlatform(IFileSystem fileSystem) : IUpdatePlatform
return release.Assets.FirstOrDefault(asset => asset.BrowserDownloadUrl.EndsWith(".exe", StringComparison.OrdinalIgnoreCase));
}

public async Task<OperationResult> ExecuteUpdateAsync(string downloadUrl)
public async Task<OperationResult> ExecuteUpdateAsync(string downloadUrl, bool restartApplication = true)
{
if (!restartApplication)
return await UpdateAsync(downloadUrl, restartApplication: false);

// If running as administrator, update immediately.
if (IsAdministrator())
return await UpdateAsync(downloadUrl);
Expand Down Expand Up @@ -63,7 +66,7 @@ private static bool IsAdministrator()
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}

private async Task<OperationResult> UpdateAsync(string downloadUrl)
private async Task<OperationResult> UpdateAsync(string downloadUrl, bool restartApplication = true)
{
var currentExecutablePath = Environment.ProcessPath;
if (currentExecutablePath is null)
Expand Down Expand Up @@ -95,7 +98,7 @@ private async Task<OperationResult> UpdateAsync(string downloadUrl)
await Task.Delay(200);

// Create and run the PowerShell script to perform the update.
var scriptResult = CreateAndRunPowerShellScript(currentExecutablePath, newFilePath);
var scriptResult = CreateAndRunPowerShellScript(currentExecutablePath, newFilePath, restartApplication);
if (scriptResult.IsFailure)
return scriptResult;

Expand All @@ -104,7 +107,7 @@ private async Task<OperationResult> UpdateAsync(string downloadUrl)
return Ok();
}

private OperationResult CreateAndRunPowerShellScript(string currentFilePath, string newFilePath)
private OperationResult CreateAndRunPowerShellScript(string currentFilePath, string newFilePath, bool restartApplication)
{
var currentFolder = fileSystem.Path.GetDirectoryName(currentFilePath);
if (currentFolder is null)
Expand All @@ -114,6 +117,10 @@ private OperationResult CreateAndRunPowerShellScript(string currentFilePath, str
var originalFileName = fileSystem.Path.GetFileName(currentFilePath);
var newFileName = fileSystem.Path.GetFileName(newFilePath);

var restartCommand = restartApplication
? $"Start-Process -FilePath {EnvHelper.SingleQuotePath(fileSystem.Path.Combine(currentFolder, originalFileName))}"
: string.Empty;

var scriptContent = $$"""

Write-Output 'Starting update process...'
Expand Down Expand Up @@ -161,7 +168,7 @@ exit 1
}

Write-Output 'Starting the updated application...'
Start-Process -FilePath {{EnvHelper.SingleQuotePath(fileSystem.Path.Combine(currentFolder, originalFileName))}}
{{restartCommand}}

Write-Output 'Cleaning up...'
Remove-Item -Path {{EnvHelper.SingleQuotePath(scriptFilePath)}} -Force
Expand Down
26 changes: 26 additions & 0 deletions WheelWizard/Views/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.Logging;
using WheelWizard.AutoUpdating;
using WheelWizard.CustomDistributions;
using WheelWizard.MiiRendering.Services;
using WheelWizard.Mods;
using WheelWizard.Services;
Expand Down Expand Up @@ -117,6 +118,9 @@ private static StartupLaunchTarget GetStartupLaunchTarget()
return StartupLaunchTarget.None;
}

private static bool IsUpdateOnlyRequested() =>
Environment.GetCommandLineArgs().Skip(1).Any(argument => argument.Equals("--updateonly", StringComparison.OrdinalIgnoreCase));

private static async Task<bool> OpenGameBananaModWindowAsync()
{
var protocolArgument = GetLaunchProtocolArgument();
Expand Down Expand Up @@ -197,6 +201,12 @@ private async Task InitializeDesktopAsync(IClassicDesktopStyleApplicationLifetim
{
try
{
if (IsUpdateOnlyRequested())
{
await RunUpdateOnlyAsync(desktop);
return;
}

var resourceInstaller = Services.GetRequiredService<IMiiRenderingResourceInstaller>();
if (resourceInstaller.GetResolvedResourcePath().IsFailure)
{
Expand Down Expand Up @@ -225,4 +235,20 @@ private async Task InitializeDesktopAsync(IClassicDesktopStyleApplicationLifetim
desktop.Shutdown();
}
}

private static async Task RunUpdateOnlyAsync(IClassicDesktopStyleApplicationLifetime desktop)
{
var logger = Services.GetRequiredService<ILogger<App>>();
var distributions = Services.GetRequiredService<ICustomDistributionSingletonService>();

if (distributions.RetroRewind.GetCurrentVersion() is not null)
{
var updateResult = await Services.GetRequiredService<RrLauncher>().Update();
if (updateResult.IsFailure)
logger.LogError(updateResult.Error.Exception, "Failed to update Retro Rewind: {Message}", updateResult.Error.Message);
}

await Services.GetRequiredService<IAutoUpdaterSingletonService>().CheckForUpdatesAsync(updateAutomatically: true);
desktop.Shutdown();
}
}
Loading