Installed & portable mode: Enhance auto updates (#142)

* Add handling of portable mode when updating

Additionally: 
1. Changed getting version from internally rather than from RELEASES file
2. Added PortableDataPath as a constant so can be used  to determine if portable mode is used

* Fix incorrectly wired auto update event handler

* Fix Sys plugin missing Shutdown command icon

* Add check update command to Sys plugin

* Add message if current Wox version is latest

* Add default silent when auto checking updates in background

Silent when current is still the latest version

* Move UserData folder to new version location

* Changes per review

1. Move IsPortableMode to Constant
2. Merge if statement

* Per comment- change variables to be more descriptive

UpdateInfo and UpdateManager renamed

* Per comment- Add exception handling and message if failed.
This commit is contained in:
Jeremy Wu 2020-02-25 21:08:51 +11:00 committed by GitHub
parent 73705bec23
commit cecb65cd40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 201 additions and 43 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -234,6 +234,20 @@ namespace Wox.Plugin.Sys
context.API.GetTranslation("wox_plugin_sys_dlgtext_all_applicableplugins_reloaded")); context.API.GetTranslation("wox_plugin_sys_dlgtext_all_applicableplugins_reloaded"));
return true; return true;
} }
},
new Result
{
Title = "Check For Update",
SubTitle = "Check for new Wox update",
IcoPath = "Images\\checkupdate.png",
Action = c =>
{
Application.Current.MainWindow.Hide();
context.API.CheckForNewUpdate();
context.API.ShowMsg("Please wait...",
"Checking for new update");
return true;
}
} }
}); });
return results; return results;

View File

@ -71,9 +71,15 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Images\checkupdate.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="Images\recyclebin.png"> <Content Include="Images\recyclebin.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<None Include="Images\shutdown.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="Images\sleep.png"> <Content Include="Images\sleep.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
@ -10,9 +10,11 @@ using JetBrains.Annotations;
using Squirrel; using Squirrel;
using Newtonsoft.Json; using Newtonsoft.Json;
using Wox.Core.Resource; using Wox.Core.Resource;
using Wox.Plugin.SharedCommands;
using Wox.Infrastructure; using Wox.Infrastructure;
using Wox.Infrastructure.Http; using Wox.Infrastructure.Http;
using Wox.Infrastructure.Logger; using Wox.Infrastructure.Logger;
using System.IO;
namespace Wox.Core namespace Wox.Core
{ {
@ -25,14 +27,14 @@ namespace Wox.Core
GitHubRepository = gitHubRepository; GitHubRepository = gitHubRepository;
} }
public async Task UpdateApp() public async Task UpdateApp(bool silentIfLatestVersion = true)
{ {
UpdateManager m; UpdateManager updateManager;
UpdateInfo u; UpdateInfo newUpdateInfo;
try try
{ {
m = await GitHubUpdateManager(GitHubRepository); updateManager = await GitHubUpdateManager(GitHubRepository);
} }
catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
{ {
@ -43,42 +45,61 @@ namespace Wox.Core
try try
{ {
// UpdateApp CheckForUpdate will return value only if the app is squirrel installed // UpdateApp CheckForUpdate will return value only if the app is squirrel installed
u = await m.CheckForUpdate().NonNull(); newUpdateInfo = await updateManager.CheckForUpdate().NonNull();
} }
catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
{ {
Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to api.github.com.", e); Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to api.github.com.", e);
m.Dispose(); updateManager.Dispose();
return; return;
} }
var fr = u.FutureReleaseEntry; var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString());
var cr = u.CurrentlyInstalledVersion; var currentVersion = Version.Parse(Constant.Version);
Log.Info($"|Updater.UpdateApp|Future Release <{fr.Formatted()}>");
if (fr.Version > cr.Version) Log.Info($"|Updater.UpdateApp|Future Release <{newUpdateInfo.FutureReleaseEntry.Formatted()}>");
if (newReleaseVersion <= currentVersion)
{ {
try if (!silentIfLatestVersion)
{ MessageBox.Show("You already have the latest Wox version");
await m.DownloadReleases(u.ReleasesToApply); updateManager.Dispose();
} return;
catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
{
Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
m.Dispose();
return;
}
await m.ApplyReleases(u);
await m.CreateUninstallerRegistryEntry();
var newVersionTips = this.NewVersinoTips(fr.Version.ToString());
MessageBox.Show(newVersionTips);
Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}");
} }
try
{
await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply);
}
catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
{
Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
updateManager.Dispose();
return;
}
await updateManager.ApplyReleases(newUpdateInfo);
if (Constant.IsPortableMode)
{
var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{Constant.PortableFolderName}";
FilesFolders.Copy(Constant.PortableDataPath, targetDestination);
if (!FilesFolders.VerifyBothFolderFilesEqual(Constant.PortableDataPath, targetDestination))
MessageBox.Show(string.Format("Wox was not able to move your user profile data to the new update version. Please manually" +
"move your profile data folder from {0} to {1}", Constant.PortableDataPath, targetDestination));
}
else
{
await updateManager.CreateUninstallerRegistryEntry();
}
var newVersionTips = NewVersinoTips(newReleaseVersion.ToString());
MessageBox.Show(newVersionTips);
Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}");
// always dispose UpdateManager // always dispose UpdateManager
m.Dispose(); updateManager.Dispose();
} }
[UsedImplicitly] [UsedImplicitly]

View File

@ -7,12 +7,22 @@ namespace Wox.Infrastructure
{ {
public static class Constant public static class Constant
{ {
public const string Wox = "Wox";
public const string Plugins = "Plugins";
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location.NonNull()).ToString();
public static readonly string ExecutablePath = Path.Combine(ProgramDirectory, Wox + ".exe");
public static bool IsPortableMode;
public const string PortableFolderName = "UserData";
public static string PortableDataPath = Path.Combine(ProgramDirectory, PortableFolderName);
public static string DetermineDataDirectory() public static string DetermineDataDirectory()
{ {
string portableDataPath = Path.Combine(ProgramDirectory, "UserData"); if (Directory.Exists(PortableDataPath))
if (Directory.Exists(portableDataPath))
{ {
return portableDataPath; IsPortableMode = true;
return PortableDataPath;
} }
else else
{ {
@ -20,12 +30,6 @@ namespace Wox.Infrastructure
} }
} }
public const string Wox = "Wox";
public const string Plugins = "Plugins";
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location.NonNull()).ToString();
public static readonly string ExecutablePath = Path.Combine(ProgramDirectory, Wox + ".exe");
public static readonly string DataDirectory = DetermineDataDirectory(); public static readonly string DataDirectory = DetermineDataDirectory();
public static readonly string PluginsDirectory = Path.Combine(DataDirectory, Plugins); public static readonly string PluginsDirectory = Path.Combine(DataDirectory, Plugins);
public static readonly string PreinstalledDirectory = Path.Combine(ProgramDirectory, Plugins); public static readonly string PreinstalledDirectory = Path.Combine(ProgramDirectory, Plugins);

View File

@ -70,6 +70,11 @@ namespace Wox.Plugin
/// </summary> /// </summary>
void ReloadAllPluginData(); void ReloadAllPluginData();
/// <summary>
/// Check for new Wox update
/// </summary>
void CheckForNewUpdate();
/// <summary> /// <summary>
/// Show message box /// Show message box
/// </summary> /// </summary>

View File

@ -0,0 +1,101 @@
using System;
using System.IO;
using System.Windows;
namespace Wox.Plugin.SharedCommands
{
public static class FilesFolders
{
public static void Copy(this string sourcePath, string targetPath)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourcePath);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourcePath);
}
try
{
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(targetPath))
{
Directory.CreateDirectory(targetPath);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(targetPath, file.Name);
file.CopyTo(temppath, false);
}
// Recursively copy subdirectories by calling itself on each subdirectory until there are no more to copy
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(targetPath, subdir.Name);
Copy(subdir.FullName, temppath);
}
}
catch (Exception e)
{
#if DEBUG
throw e;
#else
MessageBox.Show(string.Format("Copying path {0} has failed, it will now be deleted for consistency", targetPath));
RemoveFolder(targetPath);
#endif
}
}
public static bool VerifyBothFolderFilesEqual(this string fromPath, string toPath)
{
try
{
var fromDir = new DirectoryInfo(fromPath);
var toDir = new DirectoryInfo(toPath);
if (fromDir.GetFiles("*", SearchOption.AllDirectories).Length != toDir.GetFiles("*", SearchOption.AllDirectories).Length)
return false;
if (fromDir.GetDirectories("*", SearchOption.AllDirectories).Length != toDir.GetDirectories("*", SearchOption.AllDirectories).Length)
return false;
return true;
}
catch (Exception e)
{
#if DEBUG
throw e;
#else
MessageBox.Show(string.Format("Unable to verify folders and files between {0} and {1}", fromPath, toPath));
return false;
#endif
}
}
public static void RemoveFolder(this string path)
{
try
{
if (Directory.Exists(path))
Directory.Delete(path, true);
}
catch (Exception e)
{
#if DEBUG
throw e;
#else
MessageBox.Show(string.Format("Not able to delete folder {0}, please go to the location and manually delete it", path));
#endif
}
}
}
}

View File

@ -65,6 +65,7 @@
<Compile Include="Query.cs" /> <Compile Include="Query.cs" />
<Compile Include="Result.cs" /> <Compile Include="Result.cs" />
<Compile Include="ActionContext.cs" /> <Compile Include="ActionContext.cs" />
<Compile Include="SharedCommands\FilesFolders.cs" />
<Compile Include="SharedCommands\SearchWeb.cs" /> <Compile Include="SharedCommands\SearchWeb.cs" />
<Compile Include="SharedCommands\ShellCommand.cs" /> <Compile Include="SharedCommands\ShellCommand.cs" />
</ItemGroup> </ItemGroup>

View File

@ -5,6 +5,7 @@ using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using Squirrel; using Squirrel;
using Wox.Core;
using Wox.Core.Plugin; using Wox.Core.Plugin;
using Wox.Core.Resource; using Wox.Core.Resource;
using Wox.Helper; using Wox.Helper;
@ -65,6 +66,11 @@ namespace Wox
UpdateManager.RestartApp(); UpdateManager.RestartApp();
} }
public void CheckForNewUpdate()
{
_settingsVM.UpdateApp();
}
public void SaveAppAllSettings() public void SaveAppAllSettings()
{ {
_mainVM.Save(); _mainVM.Save();

View File

@ -33,7 +33,8 @@
<TabControl Height="auto" SelectedIndex="0"> <TabControl Height="auto" SelectedIndex="0">
<TabItem Header="{DynamicResource general}"> <TabItem Header="{DynamicResource general}">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<CheckBox IsChecked="{Binding Settings.StartWoxOnSystemStartup}" Margin="10"> <CheckBox Margin="10" IsChecked="{Binding Settings.StartWoxOnSystemStartup}"
Checked="OnAutoStartupChecked" Unchecked="OnAutoStartupUncheck">
<TextBlock Text="{DynamicResource startWoxOnSystemStartup}" /> <TextBlock Text="{DynamicResource startWoxOnSystemStartup}" />
</CheckBox> </CheckBox>
<CheckBox Margin="10" IsChecked="{Binding Settings.HideOnStartup}"> <CheckBox Margin="10" IsChecked="{Binding Settings.HideOnStartup}">
@ -51,8 +52,7 @@
<CheckBox Margin="10" IsChecked="{Binding Settings.IgnoreHotkeysOnFullscreen}"> <CheckBox Margin="10" IsChecked="{Binding Settings.IgnoreHotkeysOnFullscreen}">
<TextBlock Text="{DynamicResource ignoreHotkeysOnFullscreen}" /> <TextBlock Text="{DynamicResource ignoreHotkeysOnFullscreen}" />
</CheckBox> </CheckBox>
<CheckBox Margin="10" IsChecked="{Binding Settings.AutoUpdates}" <CheckBox Margin="10" IsChecked="{Binding Settings.AutoUpdates}">
Checked="OnAutoStartupChecked" Unchecked="OnAutoStartupUncheck">
<TextBlock Text="{DynamicResource autoUpdates}" /> <TextBlock Text="{DynamicResource autoUpdates}" />
</CheckBox> </CheckBox>
<CheckBox Margin="10" IsChecked="{Binding Settings.ShouldUsePinyin}"> <CheckBox Margin="10" IsChecked="{Binding Settings.ShouldUsePinyin}">

View File

@ -44,7 +44,7 @@ namespace Wox.ViewModel
public async void UpdateApp() public async void UpdateApp()
{ {
await _updater.UpdateApp(); await _updater.UpdateApp(false);
} }
public void Save() public void Save()