Skip to content

Commit

Permalink
Add fallback support when update install fails
Browse files Browse the repository at this point in the history
  • Loading branch information
X9VoiD committed Jun 22, 2023
1 parent 5e91774 commit 1968baa
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 17 deletions.
66 changes: 49 additions & 17 deletions OpenTabletDriver.Desktop/Updater/Updater.cs
Expand Up @@ -63,8 +63,8 @@ public Task Install(Update update)
try
{
UpdateInstalling?.Invoke(update);
PrepareForUpdate(update);
InstallUpdate(update);
PrepareForUpdate(update, out var binaryRollback);
InstallUpdate(update, binaryRollback);
installed = true;
}
finally
Expand All @@ -81,51 +81,72 @@ public Task Install(Update update)
return Task.CompletedTask;
}

private void InstallUpdate(Update update)
private void InstallUpdate(Update update, string binaryRollback)
{
foreach (var source in update.Paths)
try
{
var destination = Path.Join(BinaryDirectory, Path.GetFileName(source));
foreach (var source in update.Paths)
{
var destination = Path.Join(BinaryDirectory, Path.GetFileName(source));

if (File.Exists(source))
File.Move(source, destination);
else if (Directory.Exists(source))
Directory.Move(source, destination);
if (File.Exists(source))
File.Move(source, destination);
else if (Directory.Exists(source))
Directory.Move(source, destination);
}
}
catch (Exception ex)
{
// redo the binary rollback and this time copy the files instead of moving them
Backup(binaryRollback, update.Paths, Copy, Copy);

// and then run fallback procedure
InstallUpdateFallback(update, ex);
}
}

protected abstract Task<UpdateInfo?> CheckForUpdatesCore();

protected void PrepareForUpdate(Update update)
protected virtual void InstallUpdateFallback(Update update, Exception ex)
{
// throw by default
throw new UpdateInstallFailedException(ex);
}

protected void PrepareForUpdate(Update update, out string binaryRollback)
{
string timestamp = DateTime.UtcNow.ToString("-yyyy-MM-dd_hh-mm-ss");
var rollback = Path.Join(RollbackDirectory, CurrentVersion + timestamp);
var binaryRollback = Path.Join(rollback, "bin");
binaryRollback = Path.Join(rollback, "bin");
var appDataRollback = Path.Join(rollback, "appdata");

Directory.CreateDirectory(rollback);
Directory.CreateDirectory(binaryRollback);
Directory.CreateDirectory(appDataRollback);

Backup(binaryRollback, update.Paths);
// Moves files/directories that would be updated to a rollback directory.
// Doing a move is necessary for Windows to allow the update to overwrite the files.
Backup(binaryRollback, update.Paths, File.Move, Directory.Move);
BackupAppData(appDataRollback);

RollbackCreated?.Invoke(rollback);
}

// Moves files/directories that would be updated to a rollback directory.
// Doing a move is necessary for Windows to allow the update to overwrite the files.
protected void Backup(string binaryRollback, ImmutableArray<string> pathsToUpdate)
private void Backup(
string binaryRollback,
ImmutableArray<string> pathsToUpdate,
Action<string, string> fileAction,
Action<string, string> directoryAction)
{
foreach (var path in pathsToUpdate.Select(f => Path.GetFileName(f)))
{
var source = Path.Join(BinaryDirectory, path);
var destination = Path.Join(binaryRollback, path);

if (File.Exists(source))
File.Move(source, destination);
fileAction(source, destination);
else if (Directory.Exists(source))
Directory.Move(source, destination);
directoryAction(source, destination);
}
}

Expand Down Expand Up @@ -184,4 +205,15 @@ public UpdateAlreadyInstalledException() : base("An update has already been inst
{
}
}

public class UpdateInstallFailedException : Exception
{
public UpdateInstallFailedException() : base("Failed to install update.")
{
}

public UpdateInstallFailedException(Exception innerException) : base("Failed to install update.", innerException)
{
}
}
}
58 changes: 58 additions & 0 deletions OpenTabletDriver.Desktop/Updater/WindowsUpdater.cs
@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Octokit;

Expand All @@ -18,6 +21,61 @@ public WindowsUpdater(AppInfo appInfo, IGitHubClient client)
{
}

protected override void InstallUpdateFallback(Update update, Exception ex)
{
var targetProcesses = new string[] {
"OpenTabletDriver.UX.Wpf.exe",
"OpenTabletDriver.Daemon.exe",
"OpenTabletDriver.Console.exe",
};

var batchCommands = new List<string>()
{
"@echo off"
};

// Kill all processes that are being updated
batchCommands.AddRange(targetProcesses
.Select(p => $"taskkill /F /IM \"{p}\" > nul"));

// Install the update
batchCommands.AddRange(update.Paths
.Select(p => $"move /Y \"{p}\" \"{BinaryDirectory}\""));

// Start the updated process
batchCommands.Add(
$$"""
set "executable="
for /R "{{BinaryDirectory}}" %%F in (OpenTabletDriver.UI*) do (
if not defined executable (
set "executable=%%F"
)
)

if defined executable (
start "" "%executable%"
) else (
start "" "{{Path.Join(BinaryDirectory, "OpenTabletDriver.UX.Wpf.exe")}}"
)
"""
);

var batchCommand = string.Join("\n", batchCommands);
var updateScript = Path.Join(Path.GetTempPath(), Path.GetRandomFileName() + ".bat");
File.WriteAllText(updateScript, batchCommand);

var processInfo = new ProcessStartInfo()
{
FileName = updateScript,
CreateNoWindow = true,
UseShellExecute = false,
WorkingDirectory = BinaryDirectory,
};

Process.Start(processInfo);
Thread.Sleep(Timeout.Infinite);
}

protected override async Task<Update> Download(Release release, Version version)
{
var downloadPath = GetDownloadPath();
Expand Down

0 comments on commit 1968baa

Please sign in to comment.