diff --git a/.releaseindex.json b/.releaseindex.json new file mode 100644 index 00000000..ea258888 --- /dev/null +++ b/.releaseindex.json @@ -0,0 +1,5 @@ +{ + "Linux":"Libation.\\d+.\\d+.\\d+-linux-chardonnay", + "WindowsClassic":"Libation.\\d+.\\d+.\\d+-win-classic.zip", + "WindowsAvalonia":"Libation.\\d+.\\d+.\\d+-win-chardonnay" +} diff --git a/Source/AppScaffolding/LibationScaffolding.cs b/Source/AppScaffolding/LibationScaffolding.cs index c5ba959f..c2bdce85 100644 --- a/Source/AppScaffolding/LibationScaffolding.cs +++ b/Source/AppScaffolding/LibationScaffolding.cs @@ -309,10 +309,17 @@ namespace AppScaffolding LibraryCommands.BookUserDefinedItemCommitted += (_, books) => SearchEngineCommands.UpdateBooks(books); } - public static UpgradeProperties GetLatestRelease() + public enum ReleaseIdentifier + { + WindowsClassic, + WindowsAvalonia, + Linux + } + + public static UpgradeProperties GetLatestRelease(ReleaseIdentifier releaseID = ReleaseIdentifier.WindowsClassic) { // timed out - var latest = getLatestRelease(TimeSpan.FromSeconds(10)); + var latest = getLatestRelease(TimeSpan.FromSeconds(10), releaseID); if (latest is null) return null; @@ -337,11 +344,11 @@ namespace AppScaffolding return new(zipUrl, latest.HtmlUrl, zip.Name, latestRelease); } - private static Octokit.Release getLatestRelease(TimeSpan timeout) + private static Octokit.Release getLatestRelease(TimeSpan timeout, ReleaseIdentifier releaseID) { try { - var task = System.Threading.Tasks.Task.Run(() => getLatestRelease()); + var task = getLatestRelease(releaseID); if (task.Wait(timeout)) return task.Result; @@ -353,13 +360,20 @@ namespace AppScaffolding } return null; } - private static Octokit.Release getLatestRelease() + private static async System.Threading.Tasks.Task getLatestRelease(ReleaseIdentifier releaseID) { var gitHubClient = new Octokit.GitHubClient(new Octokit.ProductHeaderValue("Libation")); + //Download the release index + var bts = await gitHubClient.Repository.Content.GetRawContent("Mbucari", "Libation", ".releaseindex.json"); + var releaseIndex = JObject.Parse(System.Text.Encoding.ASCII.GetString(bts)); + var regexPattern = releaseIndex.Value(releaseID.ToString()); + // https://octokitnet.readthedocs.io/en/latest/releases/ - var releases = gitHubClient.Repository.Release.GetAll("rmcrackan", "Libation").GetAwaiter().GetResult(); - var latest = releases.First(r => !r.Draft && !r.Prerelease); + var releases = await gitHubClient.Repository.Release.GetAll("rmcrackan", "Libation"); + + var regex = new System.Text.RegularExpressions.Regex(regexPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase); + var latest = releases.FirstOrDefault(r => !r.Draft && !r.Prerelease && r.Assets.Any(a => regex.IsMatch(a.Name))); return latest; } } diff --git a/Source/LibationAvalonia/LibationAvalonia.csproj b/Source/LibationAvalonia/LibationAvalonia.csproj index 572e61f6..06e66b4d 100644 --- a/Source/LibationAvalonia/LibationAvalonia.csproj +++ b/Source/LibationAvalonia/LibationAvalonia.csproj @@ -129,6 +129,9 @@ Always + + Always + \ No newline at end of file diff --git a/Source/LibationAvalonia/MessageBox.cs b/Source/LibationAvalonia/MessageBox.cs index 3d25be05..f92eedde 100644 --- a/Source/LibationAvalonia/MessageBox.cs +++ b/Source/LibationAvalonia/MessageBox.cs @@ -149,7 +149,11 @@ Libation. private static DialogResult ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) + => Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => ShowCoreAsync2(owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition)).GetAwaiter().GetResult(); + + private static DialogResult ShowCoreAsync2(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) { + owner ??= (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow; var dialog = new MessageBoxWindow(saveAndRestorePosition); diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs index f8f0d155..7f6cd23d 100644 --- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs @@ -8,8 +8,7 @@ using LibationAvalonia.ViewModels; using LibationFileManager; using DataLayer; using System.Collections.Generic; -using System.Linq; -using LibationAvalonia.Dialogs; +using System.Threading.Tasks; namespace LibationAvalonia.Views { @@ -67,11 +66,88 @@ namespace LibationAvalonia.Views private async void MainWindow_Opened(object sender, EventArgs e) { - /* - var charReplace = new EditReplacementChars(); +#if !DEBUG + if (App.IsWindows) + { + try + { + await Task.Run(checkForAndDownloadUpdate); + } + catch(Exception ex) + { + Serilog.Log.Logger.Error(ex, "An error occured while checking for app updates."); + return; + } + } +#endif + } - await charReplace.ShowDialog(this); - */ + private async Task checkForAndDownloadUpdate() + { + AppScaffolding.UpgradeProperties upgradeProperties; + try + { + upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(AppScaffolding.LibationScaffolding.ReleaseIdentifier.WindowsAvalonia); + + if (upgradeProperties is null) + return; + } + catch (Exception ex) + { + Serilog.Log.Logger.Error(ex, "Failed to check for update"); + return; + } + + if (upgradeProperties.ZipUrl is null) + { + Serilog.Log.Logger.Information("Download link for new version not found"); + return; + } + + //Silently download the update in the background, save it to a temp file. + + var zipPath = System.IO.Path.GetTempFileName(); + try + { + System.Net.Http.HttpClient cli = new(); + using (var fs = System.IO.File.OpenWrite(zipPath)) + { + using (var dlStream = await cli.GetStreamAsync(new Uri(upgradeProperties.ZipUrl))) + await dlStream.CopyToAsync(fs); + } + } + catch (Exception ex) + { + Serilog.Log.Logger.Error(ex, "Failed to download the update: {pdate}", upgradeProperties.ZipUrl); + return; + } + + var result = MessageBox.Show($"{upgradeProperties.HtmlUrl}\r\n\r\nWould you like to upgrade now?", "New version available", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); + + if (result != DialogResult.Yes) + return; + + var thisExe = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; + var thisDir = System.IO.Path.GetDirectoryName(thisExe); + + var args = $"--input {zipPath} --output {thisDir} --executable {thisExe}"; + + var zipExtractor = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ZipExtractor.exe"); + + System.IO.File.Copy("ZipExtractor.exe", zipExtractor, overwrite: true); + + var psi = new System.Diagnostics.ProcessStartInfo() + { + FileName = zipExtractor, + UseShellExecute = true, + Verb = "runas", + WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal, + Arguments = args, + CreateNoWindow = true + }; + + System.Diagnostics.Process.Start(psi); + Environment.Exit(0); } public void ProductsDisplay_Initialized1(object sender, EventArgs e) diff --git a/Source/LibationAvalonia/ZipExtractor.exe b/Source/LibationAvalonia/ZipExtractor.exe new file mode 100644 index 00000000..29e0a3b3 Binary files /dev/null and b/Source/LibationAvalonia/ZipExtractor.exe differ diff --git a/Source/LibationWinForms/Program.cs b/Source/LibationWinForms/Program.cs index 29d49a92..36b174a2 100644 --- a/Source/LibationWinForms/Program.cs +++ b/Source/LibationWinForms/Program.cs @@ -170,7 +170,7 @@ namespace LibationWinForms try { - upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(); + upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease(AppScaffolding.LibationScaffolding.ReleaseIdentifier.WindowsClassic); if (upgradeProperties is null) return; }