New feature ( #153 ): in-place upgrade
This commit is contained in:
parent
b9e789bbcf
commit
98c3940297
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<Version>7.6.3.1</Version>
|
<Version>7.7.0.1</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -282,22 +282,20 @@ namespace AppScaffolding
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (bool hasUpgrade, string zipUrl, string htmlUrl, string zipName) GetLatestRelease()
|
public static UpgradeProperties GetLatestRelease()
|
||||||
{
|
{
|
||||||
(bool, string, string, string) isFalse = (false, null, null, null);
|
|
||||||
|
|
||||||
// timed out
|
// timed out
|
||||||
var latest = getLatestRelease(TimeSpan.FromSeconds(10));
|
var latest = getLatestRelease(TimeSpan.FromSeconds(10));
|
||||||
if (latest is null)
|
if (latest is null)
|
||||||
return isFalse;
|
return null;
|
||||||
|
|
||||||
var latestVersionString = latest.TagName.Trim('v');
|
var latestVersionString = latest.TagName.Trim('v');
|
||||||
if (!Version.TryParse(latestVersionString, out var latestRelease))
|
if (!Version.TryParse(latestVersionString, out var latestRelease))
|
||||||
return isFalse;
|
return null;
|
||||||
|
|
||||||
// we're up to date
|
// we're up to date
|
||||||
if (latestRelease <= BuildVersion)
|
if (latestRelease <= BuildVersion)
|
||||||
return isFalse;
|
return null;
|
||||||
|
|
||||||
// we have an update
|
// we have an update
|
||||||
var zip = latest.Assets.FirstOrDefault(a => a.BrowserDownloadUrl.EndsWith(".zip"));
|
var zip = latest.Assets.FirstOrDefault(a => a.BrowserDownloadUrl.EndsWith(".zip"));
|
||||||
@ -310,7 +308,7 @@ namespace AppScaffolding
|
|||||||
zipUrl
|
zipUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
return (true, zipUrl, latest.HtmlUrl, zip.Name);
|
return new(zipUrl, latest.HtmlUrl, zip.Name, latestRelease);
|
||||||
}
|
}
|
||||||
private static Octokit.Release getLatestRelease(TimeSpan timeout)
|
private static Octokit.Release getLatestRelease(TimeSpan timeout)
|
||||||
{
|
{
|
||||||
|
|||||||
6
Source/AppScaffolding/UpgradeProperties.cs
Normal file
6
Source/AppScaffolding/UpgradeProperties.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AppScaffolding
|
||||||
|
{
|
||||||
|
public record UpgradeProperties(string ZipUrl, string HtmlUrl, string ZipName, Version LatestRelease);
|
||||||
|
}
|
||||||
@ -12,7 +12,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dinah.EntityFrameworkCore" Version="4.0.1.1" />
|
<PackageReference Include="Dinah.EntityFrameworkCore" Version="4.1.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.5">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
@ -29,7 +29,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="appsettings.json">
|
<None Update="migrate.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Dinah.Core.Net.Http;
|
|
||||||
|
|
||||||
namespace FileLiberator
|
|
||||||
{
|
|
||||||
// currently only used to download the .zip flies for upgrade
|
|
||||||
public class DownloadFile : Streamable
|
|
||||||
{
|
|
||||||
public async Task<string> PerformDownloadFileAsync(string downloadUrl, string proposedDownloadFilePath)
|
|
||||||
{
|
|
||||||
var client = new HttpClient();
|
|
||||||
|
|
||||||
var progress = new Progress<DownloadProgress>(OnStreamingProgressChanged);
|
|
||||||
|
|
||||||
OnStreamingBegin(proposedDownloadFilePath);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var actualDownloadedFilePath = await client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, progress);
|
|
||||||
OnFileCreated("Upgrade", actualDownloadedFilePath);
|
|
||||||
return actualDownloadedFilePath;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
OnStreamingCompleted(proposedDownloadFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,7 +9,6 @@ using FileLiberator;
|
|||||||
|
|
||||||
namespace LibationCli
|
namespace LibationCli
|
||||||
{
|
{
|
||||||
// streamlined, non-Forms copy of ProcessorAutomationController
|
|
||||||
public abstract class ProcessableOptionsBase : OptionsBase
|
public abstract class ProcessableOptionsBase : OptionsBase
|
||||||
{
|
{
|
||||||
protected static TProcessable CreateProcessable<TProcessable>(EventHandler<LibraryBook> completedAction = null)
|
protected static TProcessable CreateProcessable<TProcessable>(EventHandler<LibraryBook> completedAction = null)
|
||||||
|
|||||||
@ -34,15 +34,15 @@ namespace LibationCli
|
|||||||
|
|
||||||
private static void checkForUpdate()
|
private static void checkForUpdate()
|
||||||
{
|
{
|
||||||
var (hasUpgrade, zipUrl, htmlUrl, zipName) = LibationScaffolding.GetLatestRelease();
|
var upgradeProperties = LibationScaffolding.GetLatestRelease();
|
||||||
if (!hasUpgrade)
|
if (upgradeProperties is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var origColor = Console.ForegroundColor;
|
var origColor = Console.ForegroundColor;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
Console.WriteLine($"UPDATE AVAILABLE @ {zipUrl}");
|
Console.WriteLine($"UPDATE AVAILABLE @ {upgradeProperties.ZipUrl}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@ -421,7 +421,7 @@ namespace LibationFileManager
|
|||||||
return libationFilesPathCache;
|
return libationFilesPathCache;
|
||||||
|
|
||||||
// FIRST: must write here before SettingsFilePath in next step reads cache
|
// FIRST: must write here before SettingsFilePath in next step reads cache
|
||||||
libationFilesPathCache = getLiberationFilesSettingFromJson();
|
libationFilesPathCache = getLibationFilesSettingFromJson();
|
||||||
|
|
||||||
// SECOND. before setting to json file with SetWithJsonPath, PersistentDictionary must exist
|
// SECOND. before setting to json file with SetWithJsonPath, PersistentDictionary must exist
|
||||||
persistentDictionary = new PersistentDictionary(SettingsFilePath);
|
persistentDictionary = new PersistentDictionary(SettingsFilePath);
|
||||||
@ -443,7 +443,7 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
private static string libationFilesPathCache;
|
private static string libationFilesPathCache;
|
||||||
|
|
||||||
private string getLiberationFilesSettingFromJson()
|
private string getLibationFilesSettingFromJson()
|
||||||
{
|
{
|
||||||
string startingContents = null;
|
string startingContents = null;
|
||||||
try
|
try
|
||||||
@ -482,6 +482,14 @@ namespace LibationFileManager
|
|||||||
{
|
{
|
||||||
libationFilesPathCache = null;
|
libationFilesPathCache = null;
|
||||||
|
|
||||||
|
// ensure exists
|
||||||
|
if (!File.Exists(APPSETTINGS_JSON))
|
||||||
|
{
|
||||||
|
// getter creates new file, loads PersistentDictionary
|
||||||
|
var _ = LibationFiles;
|
||||||
|
System.Threading.Thread.Sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
var startingContents = File.ReadAllText(APPSETTINGS_JSON);
|
var startingContents = File.ReadAllText(APPSETTINGS_JSON);
|
||||||
var jObj = JObject.Parse(startingContents);
|
var jObj = JObject.Parse(startingContents);
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||||
<PackageReference Include="Serilog.Exceptions" Version="8.1.0" />
|
<PackageReference Include="Serilog.Exceptions" Version="8.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Autoupdater.NET.Official" Version="1.7.0" />
|
||||||
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="4.2.2.1" />
|
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="4.2.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -3,14 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using AudibleApi.Authorization;
|
|
||||||
using AudibleUtilities;
|
|
||||||
using DataLayer;
|
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using LibationWinForms.Dialogs;
|
using LibationWinForms.Dialogs;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace LibationWinForms
|
namespace LibationWinForms
|
||||||
@ -165,15 +160,12 @@ namespace LibationWinForms
|
|||||||
|
|
||||||
private static void checkForUpdate()
|
private static void checkForUpdate()
|
||||||
{
|
{
|
||||||
string zipUrl;
|
AppScaffolding.UpgradeProperties upgradeProperties;
|
||||||
string htmlUrl;
|
|
||||||
string zipName;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool hasUpgrade;
|
upgradeProperties = AppScaffolding.LibationScaffolding.GetLatestRelease();
|
||||||
(hasUpgrade, zipUrl, htmlUrl, zipName) = AppScaffolding.LibationScaffolding.GetLatestRelease();
|
if (upgradeProperties is null)
|
||||||
|
|
||||||
if (!hasUpgrade)
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -182,36 +174,13 @@ namespace LibationWinForms
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zipUrl is null)
|
if (upgradeProperties.ZipUrl is null)
|
||||||
{
|
{
|
||||||
MessageBox.Show(htmlUrl, "New version available");
|
MessageBox.Show(upgradeProperties.HtmlUrl, "New version available");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = MessageBox.Show($"New version available @ {htmlUrl}\r\n\r\nWould you like to upgrade?", "New version available", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
Updater.Run(upgradeProperties.LatestRelease, upgradeProperties.ZipUrl);
|
||||||
if (result != DialogResult.Yes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Download the upgrader app from github
|
|
||||||
string fileName = "ht" + "tps://github.com/Mbucari/Upgrader/raw/master/Upgrader/win-x86/Upgrader.exe";
|
|
||||||
var cli = new System.Net.Http.HttpClient();
|
|
||||||
var upgrader = cli.GetByteArrayAsync(fileName).GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
|
|
||||||
string upgraderPath = Path.Combine(Path.GetTempPath(), "Upgrader.exe");
|
|
||||||
File.WriteAllBytes(upgraderPath, upgrader);
|
|
||||||
var thisExe = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
|
|
||||||
|
|
||||||
//usage is Upgrader.exe [zip url] [extract directory] [exe to launch]
|
|
||||||
System.Diagnostics.Process.Start(upgraderPath, new string[] { zipUrl, Path.GetDirectoryName(thisExe), "Libation.exe" });
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
MessageBoxLib.ShowAdminAlert("Error downloading update", "Error downloading update", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
Source/LibationWinForms/Updater.cs
Normal file
50
Source/LibationWinForms/Updater.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using AutoUpdaterDotNET;
|
||||||
|
|
||||||
|
namespace LibationWinForms
|
||||||
|
{
|
||||||
|
public static class Updater
|
||||||
|
{
|
||||||
|
private const string REPO_URL = "https://github.com/rmcrackan/Libation/releases/latest";
|
||||||
|
|
||||||
|
public static void Run(Version latestVersionOnServer, string downloadZipUrl)
|
||||||
|
=> Run(latestVersionOnServer.ToString(), downloadZipUrl);
|
||||||
|
public static void Run(string latestVersionOnServer, string downloadZipUrl)
|
||||||
|
{
|
||||||
|
AutoUpdater.ParseUpdateInfoEvent +=
|
||||||
|
args => args.UpdateInfo = new()
|
||||||
|
{
|
||||||
|
CurrentVersion = latestVersionOnServer,
|
||||||
|
DownloadURL = downloadZipUrl,
|
||||||
|
ChangelogURL = REPO_URL
|
||||||
|
};
|
||||||
|
AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent;
|
||||||
|
AutoUpdater.Start(REPO_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args)
|
||||||
|
{
|
||||||
|
if (args is null || !args.IsUpdateAvailable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dialogResult = MessageBox.Show(string.Format(
|
||||||
|
$"There is a new version avilable. Would you like to update?\r\n\r\nAfter you close Libation, the upgrade will start automatically."),
|
||||||
|
"Update Available",
|
||||||
|
MessageBoxButtons.YesNo,
|
||||||
|
MessageBoxIcon.Information);
|
||||||
|
if (dialogResult != DialogResult.Yes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Serilog.Log.Logger.Information("Start upgrade. {@DebugInfo}", new { CurrentlyInstalled = args.InstalledVersion, TargetVersion = args.CurrentVersion });
|
||||||
|
AutoUpdater.DownloadUpdate(args);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBoxLib.ShowAdminAlert("Error downloading update", "Error downloading update", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="Moq" Version="4.18.1" />
|
<PackageReference Include="Moq" Version="4.18.1" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="6.6.0" />
|
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="Moq" Version="4.18.1" />
|
<PackageReference Include="Moq" Version="4.18.1" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user