mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
migrate to velopack
This commit is contained in:
parent
1cc8b9dfe8
commit
3d6782ca30
10 changed files with 200 additions and 218 deletions
|
|
@ -5,12 +5,6 @@ namespace Flow.Launcher.Core.Configuration
|
|||
{
|
||||
void EnablePortableMode();
|
||||
void DisablePortableMode();
|
||||
void RemoveShortcuts();
|
||||
void RemoveUninstallerEntry();
|
||||
void CreateShortcuts();
|
||||
void CreateUninstallerEntry();
|
||||
void MoveUserDataFolder(string fromLocation, string toLocation);
|
||||
void VerifyUserDataAfterMove(string fromLocation, string toLocation);
|
||||
bool CanUpdatePortability();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Microsoft.Win32;
|
||||
using Squirrel;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
|
@ -9,41 +8,26 @@ using Flow.Launcher.Infrastructure.Logger;
|
|||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using System.Linq;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Velopack;
|
||||
using Velopack.Locators;
|
||||
using Velopack.Windows;
|
||||
|
||||
namespace Flow.Launcher.Core.Configuration
|
||||
{
|
||||
public class Portable : IPortable
|
||||
{
|
||||
/// <summary>
|
||||
/// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private UpdateManager NewUpdateManager()
|
||||
{
|
||||
var applicationFolderName = Constant.ApplicationDirectory
|
||||
.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None)
|
||||
.Last();
|
||||
|
||||
return new UpdateManager(string.Empty, applicationFolderName, Constant.RootDirectory);
|
||||
}
|
||||
|
||||
public void DisablePortableMode()
|
||||
{
|
||||
try
|
||||
{
|
||||
MoveUserDataFolder(DataLocation.PortableDataPath, DataLocation.RoamingDataPath);
|
||||
#if !DEBUG
|
||||
// Create shortcuts and uninstaller are not required in debug mode,
|
||||
// otherwise will repoint the path of the actual installed production version to the debug version
|
||||
CreateShortcuts();
|
||||
CreateUninstallerEntry();
|
||||
#endif
|
||||
IndicateDeletion(DataLocation.PortableDataPath);
|
||||
|
||||
MessageBox.Show("Flow Launcher needs to restart to finish disabling portable mode, " +
|
||||
"after the restart your portable data profile will be deleted and roaming data profile kept");
|
||||
"after the restart your portable data profile will be deleted and roaming data profile kept");
|
||||
|
||||
UpdateManager.RestartApp(Constant.ApplicationFileName);
|
||||
PluginManager.API.RestartApp();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -56,18 +40,12 @@ namespace Flow.Launcher.Core.Configuration
|
|||
try
|
||||
{
|
||||
MoveUserDataFolder(DataLocation.RoamingDataPath, DataLocation.PortableDataPath);
|
||||
#if !DEBUG
|
||||
// Remove shortcuts and uninstaller are not required in debug mode,
|
||||
// otherwise will delete the actual installed production version
|
||||
RemoveShortcuts();
|
||||
RemoveUninstallerEntry();
|
||||
#endif
|
||||
IndicateDeletion(DataLocation.RoamingDataPath);
|
||||
|
||||
MessageBox.Show("Flow Launcher needs to restart to finish enabling portable mode, " +
|
||||
"after the restart your roaming data profile will be deleted and portable data profile kept");
|
||||
"after the restart your roaming data profile will be deleted and portable data profile kept");
|
||||
|
||||
UpdateManager.RestartApp(Constant.ApplicationFileName);
|
||||
PluginManager.API.RestartApp();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -75,23 +53,6 @@ namespace Flow.Launcher.Core.Configuration
|
|||
}
|
||||
}
|
||||
|
||||
public void RemoveShortcuts()
|
||||
{
|
||||
using (var portabilityUpdater = NewUpdateManager())
|
||||
{
|
||||
portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.StartMenu);
|
||||
portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Desktop);
|
||||
portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveUninstallerEntry()
|
||||
{
|
||||
using (var portabilityUpdater = NewUpdateManager())
|
||||
{
|
||||
portabilityUpdater.RemoveUninstallerRegistryEntry();
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveUserDataFolder(string fromLocation, string toLocation)
|
||||
{
|
||||
|
|
@ -104,32 +65,6 @@ namespace Flow.Launcher.Core.Configuration
|
|||
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation);
|
||||
}
|
||||
|
||||
public void CreateShortcuts()
|
||||
{
|
||||
using (var portabilityUpdater = NewUpdateManager())
|
||||
{
|
||||
portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.StartMenu, false);
|
||||
portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Desktop, false);
|
||||
portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateUninstallerEntry()
|
||||
{
|
||||
var uninstallRegSubKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";
|
||||
|
||||
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default))
|
||||
using (var subKey1 = baseKey.CreateSubKey(uninstallRegSubKey, RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
using (var subKey2 = subKey1.CreateSubKey(Constant.FlowLauncher, RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
subKey2.SetValue("DisplayIcon", Path.Combine(Constant.ApplicationDirectory, "app.ico"), RegistryValueKind.String);
|
||||
}
|
||||
|
||||
using (var portabilityUpdater = NewUpdateManager())
|
||||
{
|
||||
_ = portabilityUpdater.CreateUninstallerRegistryEntry();
|
||||
}
|
||||
}
|
||||
|
||||
internal void IndicateDeletion(string filePathTodelete)
|
||||
{
|
||||
|
|
@ -145,9 +80,28 @@ namespace Flow.Launcher.Core.Configuration
|
|||
///</summary>
|
||||
public void PreStartCleanUpAfterPortabilityUpdate()
|
||||
{
|
||||
var locator = VelopackLocator.GetDefault(null);
|
||||
|
||||
// this would not happen for development environment
|
||||
if (locator.PackagesDir != null)
|
||||
{
|
||||
// check whether the package locate in %localappdata%
|
||||
// if not create the portable data folder
|
||||
if (!locator.PackagesDir.IsSubPathOf(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData))
|
||||
&& !DataLocation.PortableDataPath.LocationExists())
|
||||
{
|
||||
Directory.CreateDirectory(DataLocation.PortableDataPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Specify here so this method does not rely on other environment variables to initialise
|
||||
var portableDataDir = Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location.NonNull()).ToString(), "UserData");
|
||||
var roamingDataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FlowLauncher");
|
||||
var portableDataDir =
|
||||
Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location.NonNull()).ToString(),
|
||||
"UserData");
|
||||
var roamingDataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"FlowLauncher");
|
||||
|
||||
|
||||
// Get full path to the .dead files for each case
|
||||
var portableDataDeleteFilePath = Path.Combine(portableDataDir, DataLocation.DeletionIndicatorFile);
|
||||
|
|
@ -161,7 +115,7 @@ namespace Flow.Launcher.Core.Configuration
|
|||
|
||||
if (MessageBox.Show("Flow Launcher has detected you enabled portable mode, " +
|
||||
"would you like to move it to a different location?", string.Empty,
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
FilesFolders.OpenPath(Constant.RootDirectory);
|
||||
|
||||
|
|
@ -175,7 +129,7 @@ namespace Flow.Launcher.Core.Configuration
|
|||
FilesFolders.RemoveFolderIfExists(portableDataDir);
|
||||
|
||||
MessageBox.Show("Flow Launcher has detected you disabled portable mode, " +
|
||||
"the relevant shortcuts and uninstaller entry have been created");
|
||||
"the relevant shortcuts and uninstaller entry have been created");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,8 +141,8 @@ namespace Flow.Launcher.Core.Configuration
|
|||
if (roamingLocationExists && portableLocationExists)
|
||||
{
|
||||
MessageBox.Show(string.Format("Flow Launcher detected your user data exists both in {0} and " +
|
||||
"{1}. {2}{2}Please delete {1} in order to proceed. No changes have occurred.",
|
||||
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
|
||||
"{1}. {2}{2}Please delete {1} in order to proceed. No changes have occurred.",
|
||||
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
|
|
@ -7,7 +8,6 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using JetBrains.Annotations;
|
||||
using Squirrel;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
|
|
@ -17,8 +17,11 @@ using Flow.Launcher.Infrastructure.UserSettings;
|
|||
using Flow.Launcher.Plugin;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Windows.Shapes;
|
||||
using Velopack;
|
||||
using Velopack.Locators;
|
||||
using Velopack.Sources;
|
||||
using Path = System.IO.Path;
|
||||
|
||||
namespace Flow.Launcher.Core
|
||||
{
|
||||
|
|
@ -54,7 +57,7 @@ namespace Flow.Launcher.Core
|
|||
api.GetTranslation("update_flowlauncher_check_connection"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var newReleaseVersion = Version.Parse(newUpdateInfo.TargetFullRelease.Version.ToString());
|
||||
var currentVersion = Version.Parse(Constant.Version);
|
||||
|
||||
|
|
@ -73,23 +76,18 @@ namespace Flow.Launcher.Core
|
|||
|
||||
await updateManager.DownloadUpdatesAsync(newUpdateInfo).ConfigureAwait(false);
|
||||
|
||||
await updateManager.ApplyReleases(newUpdateInfo).ConfigureAwait(false);
|
||||
|
||||
if (DataLocation.PortableDataLocationInUse())
|
||||
{
|
||||
var targetDestination = updateManager.RootAppDirectory +
|
||||
$"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}";
|
||||
FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination);
|
||||
if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination))
|
||||
var targetDestination = Path.Combine(VelopackLocator.GetDefault(null).RootAppDir!,
|
||||
DataLocation.PortableFolderName);
|
||||
|
||||
DataLocation.PortableDataPath.CopyAll(targetDestination);
|
||||
if (!DataLocation.PortableDataPath.VerifyBothFolderFilesEqual(targetDestination))
|
||||
MessageBox.Show(string.Format(
|
||||
api.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"),
|
||||
DataLocation.PortableDataPath,
|
||||
targetDestination));
|
||||
}
|
||||
else
|
||||
{
|
||||
await updateManager.CreateUninstallerRegistryEntry().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var newVersionTips = NewVersionTips(newReleaseVersion.ToString());
|
||||
|
||||
|
|
@ -98,7 +96,11 @@ namespace Flow.Launcher.Core
|
|||
if (MessageBox.Show(newVersionTips, api.GetTranslation("update_flowlauncher_new_update"),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
UpdateManager.RestartApp(Constant.ApplicationFileName);
|
||||
updateManager.ApplyUpdatesAndRestart(newUpdateInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
updateManager.WaitExitThenApplyUpdates(newUpdateInfo);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -121,14 +123,19 @@ namespace Flow.Launcher.Core
|
|||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
private class GithubRelease
|
||||
public static void RecoverPortableData()
|
||||
{
|
||||
[JsonPropertyName("prerelease")] public bool Prerelease { get; [UsedImplicitly] set; }
|
||||
var locator = VelopackLocator.GetDefault(null);
|
||||
|
||||
[JsonPropertyName("published_at")] public DateTime PublishedAt { get; [UsedImplicitly] set; }
|
||||
var portableDataLocation = Path.Combine(VelopackLocator.GetDefault(null).RootAppDir!,
|
||||
DataLocation.PortableFolderName);
|
||||
|
||||
[JsonPropertyName("html_url")] public string HtmlUrl { get; [UsedImplicitly] set; }
|
||||
if (Path.Exists(portableDataLocation))
|
||||
{
|
||||
portableDataLocation.CopyAll(Path.Combine(locator.AppContentDir!, DataLocation.PortableFolderName));
|
||||
}
|
||||
|
||||
Directory.Delete(portableDataLocation);
|
||||
}
|
||||
|
||||
public string NewVersionTips(string version)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
#pragma warning disable IDE0005
|
||||
using System.Windows;
|
||||
|
||||
#pragma warning restore IDE0005
|
||||
|
||||
namespace Flow.Launcher.Plugin.SharedCommands
|
||||
|
|
@ -14,6 +15,18 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
{
|
||||
private const string FileExplorerProgramName = "explorer";
|
||||
|
||||
public static bool IsSubPathOf(this string subPath, string basePath)
|
||||
{
|
||||
var rel = Path.GetRelativePath(
|
||||
basePath.Replace('\\', '/'),
|
||||
subPath.Replace('\\', '/'));
|
||||
return rel != "."
|
||||
&& rel != ".."
|
||||
&& !rel.StartsWith("../")
|
||||
&& !Path.IsPathRooted(rel);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Copies the folder and all of its files and folders
|
||||
/// including subfolders to the target location
|
||||
|
|
@ -65,7 +78,6 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
RemoveFolderIfExists(targetPath);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -82,10 +94,12 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
var fromDir = new DirectoryInfo(fromPath);
|
||||
var toDir = new DirectoryInfo(toPath);
|
||||
|
||||
if (fromDir.GetFiles("*", SearchOption.AllDirectories).Length != toDir.GetFiles("*", SearchOption.AllDirectories).Length)
|
||||
if (fromDir.GetFiles("*", SearchOption.AllDirectories).Length !=
|
||||
toDir.GetFiles("*", SearchOption.AllDirectories).Length)
|
||||
return false;
|
||||
|
||||
if (fromDir.GetDirectories("*", SearchOption.AllDirectories).Length != toDir.GetDirectories("*", SearchOption.AllDirectories).Length)
|
||||
if (fromDir.GetDirectories("*", SearchOption.AllDirectories).Length !=
|
||||
toDir.GetDirectories("*", SearchOption.AllDirectories).Length)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
@ -99,7 +113,6 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -151,9 +164,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = FileExplorerProgramName,
|
||||
UseShellExecute = true,
|
||||
Arguments = '"' + fileOrFolderPath + '"'
|
||||
FileName = FileExplorerProgramName, UseShellExecute = true, Arguments = '"' + fileOrFolderPath + '"'
|
||||
};
|
||||
try
|
||||
{
|
||||
|
|
@ -279,7 +290,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
&& !rel.StartsWith(@"..\")
|
||||
&& !Path.IsPathRooted(rel);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns path ended with "\"
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,11 @@ namespace Flow.Launcher
|
|||
[STAThread]
|
||||
public static void Main()
|
||||
{
|
||||
VelopackApp.Build().Run();
|
||||
VelopackApp.Build()
|
||||
.WithAfterUpdateFastCallback(x =>
|
||||
{
|
||||
Updater.RecoverPortableData();
|
||||
}).Run();
|
||||
|
||||
if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO.Pipes;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Velopack;
|
||||
|
||||
// http://blogs.microsoft.co.il/arik/2010/05/28/wpf-single-instance-application/
|
||||
// modified to allow single instace restart
|
||||
|
|
@ -226,7 +229,6 @@ namespace Flow.Launcher.Helper
|
|||
public static void Restart()
|
||||
{
|
||||
singleInstanceMutex?.ReleaseMutex();
|
||||
|
||||
StopRemoteServiceTokenSource?.Cancel();
|
||||
|
||||
while (RemoteServiceRunning)
|
||||
|
|
@ -235,16 +237,23 @@ namespace Flow.Launcher.Helper
|
|||
Thread.Sleep(10);
|
||||
}
|
||||
|
||||
System.Diagnostics.Process.Start(Application.ResourceAssembly.Location);
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
Arguments = "/C choice /C Y /N /D Y /T 1 & START \"\" \"" + Environment.ProcessPath + "\"",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
CreateNoWindow = true,
|
||||
FileName = "cmd.exe"
|
||||
};
|
||||
Process.Start(info);
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
|
||||
// this is always going to run only once
|
||||
private static CancellationTokenSource StopRemoteServiceTokenSource { get; set; }
|
||||
|
||||
private static volatile bool RemoteServiceRunning = false;
|
||||
private static volatile bool RemoteServiceRunning = true;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the instance of the application attempting to start is the first instance.
|
||||
/// If not, activates the first instance.
|
||||
|
|
@ -252,6 +261,8 @@ namespace Flow.Launcher.Helper
|
|||
/// <returns>True if this is the first instance of the application.</returns>
|
||||
public static bool InitializeAsFirstInstance(string uniqueName)
|
||||
{
|
||||
StopRemoteServiceTokenSource = new CancellationTokenSource();
|
||||
|
||||
// Build unique application Id and the IPC channel name.
|
||||
string applicationIdentifier = uniqueName + Environment.UserName;
|
||||
|
||||
|
|
@ -261,12 +272,12 @@ namespace Flow.Launcher.Helper
|
|||
singleInstanceMutex = new Mutex(true, applicationIdentifier, out var firstInstance);
|
||||
if (firstInstance)
|
||||
{
|
||||
_ = StartRemoteServiceAsync(channelName, StopRemoteServiceTokenSource.Token);
|
||||
_ = Task.Run(() => StartRemoteServiceAsync(channelName, StopRemoteServiceTokenSource.Token));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = SignalFirstInstanceAsync(channelName);
|
||||
_ = Task.Run(() => SignalFirstInstanceAsync(channelName));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -336,27 +347,32 @@ namespace Flow.Launcher.Helper
|
|||
/// <param name="token">Cancellation token</param>
|
||||
private static async Task StartRemoteServiceAsync(string channelName, CancellationToken token = default)
|
||||
{
|
||||
await using NamedPipeServerStream pipeServer = new NamedPipeServerStream(channelName, PipeDirection.In);
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
await using NamedPipeServerStream pipeServer = new NamedPipeServerStream(channelName, PipeDirection.In);
|
||||
while (true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for connection to the pipe
|
||||
await pipeServer.WaitForConnectionAsync(token);
|
||||
if (Application.Current != null)
|
||||
{
|
||||
// Do an asynchronous call to ActivateFirstInstance function
|
||||
Application.Current.Dispatcher.Invoke(ActivateFirstInstance);
|
||||
}
|
||||
// Wait for connection to the pipe
|
||||
await pipeServer.WaitForConnectionAsync(token);
|
||||
if (Application.Current != null)
|
||||
{
|
||||
// Do an asynchronous call to ActivateFirstInstance function
|
||||
Application.Current.Dispatcher.Invoke(ActivateFirstInstance);
|
||||
}
|
||||
|
||||
// Disconnect client
|
||||
pipeServer.Disconnect();
|
||||
// Disconnect client
|
||||
pipeServer.Disconnect();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
RemoteServiceRunning = false;
|
||||
}
|
||||
|
||||
RemoteServiceRunning = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -366,7 +382,8 @@ namespace Flow.Launcher.Helper
|
|||
private static async Task SignalFirstInstanceAsync(string channelName)
|
||||
{
|
||||
// Create a client pipe connected to server
|
||||
await using NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", channelName, PipeDirection.Out);
|
||||
await using NamedPipeClientStream pipeClient =
|
||||
new NamedPipeClientStream(".", channelName, PipeDirection.Out);
|
||||
// Connect to the available pipe
|
||||
await pipeClient.ConnectAsync(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Squirrel;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace Flow.Launcher.Plugin.PluginsManager
|
||||
{
|
||||
|
|
@ -13,29 +13,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
/// <param name="overwrite">overwrite</param>
|
||||
internal static void UnZip(string zipFilePath, string strDirectory, bool overwrite)
|
||||
{
|
||||
if (strDirectory == "")
|
||||
strDirectory = Directory.GetCurrentDirectory();
|
||||
|
||||
using var zipStream = new ZipInputStream(File.OpenRead(zipFilePath));
|
||||
|
||||
ZipEntry theEntry;
|
||||
|
||||
while ((theEntry = zipStream.GetNextEntry()) != null)
|
||||
{
|
||||
var pathToZip = theEntry.Name;
|
||||
var directoryName = string.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip);
|
||||
var fileName = Path.GetFileName(pathToZip);
|
||||
var destinationDir = Path.Combine(strDirectory, directoryName);
|
||||
var destinationFile = Path.Combine(destinationDir, fileName);
|
||||
|
||||
Directory.CreateDirectory(destinationDir);
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overwrite))
|
||||
continue;
|
||||
|
||||
using var streamWriter = File.Create(destinationFile);
|
||||
zipStream.CopyTo(streamWriter);
|
||||
}
|
||||
ZipFile.ExtractToDirectory(zipFilePath, strDirectory, overwrite);
|
||||
}
|
||||
|
||||
internal static string GetContainingFolderPathAfterUnzip(string unzippedParentFolderPath)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
param(
|
||||
[string]$config = "Release",
|
||||
[string]$solution = (Join-Path $PSScriptRoot ".." -Resolve)
|
||||
[string]$config = "Release",
|
||||
[string]$solution = (Join-Path $PSScriptRoot ".." -Resolve),
|
||||
[string]$channel = "prerelease"
|
||||
)
|
||||
Write-Host "Config: $config"
|
||||
|
||||
function Build-Version {
|
||||
if ([string]::IsNullOrEmpty($env:flowVersion)) {
|
||||
function Build-Version
|
||||
{
|
||||
if ( [string]::IsNullOrEmpty($env:flowVersion))
|
||||
{
|
||||
$targetPath = Join-Path $solution "Output/Release/Flow.Launcher.dll" -Resolve
|
||||
$v = (Get-Command ${targetPath}).FileVersionInfo.FileVersion
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$v = $env:flowVersion
|
||||
}
|
||||
|
||||
|
|
@ -16,12 +21,18 @@ function Build-Version {
|
|||
return $v
|
||||
}
|
||||
|
||||
function Build-Path {
|
||||
if (![string]::IsNullOrEmpty($env:APPVEYOR_BUILD_FOLDER)) {
|
||||
function Build-Path
|
||||
{
|
||||
if (![string]::IsNullOrEmpty($env:APPVEYOR_BUILD_FOLDER))
|
||||
{
|
||||
$p = $env:APPVEYOR_BUILD_FOLDER
|
||||
} elseif (![string]::IsNullOrEmpty($solution)) {
|
||||
}
|
||||
elseif (![string]::IsNullOrEmpty($solution))
|
||||
{
|
||||
$p = $solution
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$p = Get-Location
|
||||
}
|
||||
|
||||
|
|
@ -31,23 +42,38 @@ function Build-Path {
|
|||
return $p
|
||||
}
|
||||
|
||||
function Copy-Resources ($path) {
|
||||
function Copy-Resources($path)
|
||||
{
|
||||
# making version static as multiple versions can exist in the nuget folder and in the case a breaking change is introduced.
|
||||
Copy-Item -Force $env:USERPROFILE\.nuget\packages\squirrel.windows\1.5.2\tools\Squirrel.exe $path\Output\Update.exe
|
||||
}
|
||||
|
||||
function Delete-Unused ($path, $config) {
|
||||
function Delete-Unused($path, $config)
|
||||
{
|
||||
$target = "$path\Output\$config"
|
||||
$included = Get-ChildItem $target -Filter "*.dll"
|
||||
foreach ($i in $included){
|
||||
$deleteList = Get-ChildItem $target\Plugins -Include $i -Recurse | Where { $_.VersionInfo.FileVersion -eq $i.VersionInfo.FileVersion -And $_.Name -eq "$i" }
|
||||
$deleteList | ForEach-Object{ Write-Host Deleting duplicated $_.Name with version $_.VersionInfo.FileVersion at location $_.Directory.FullName }
|
||||
$deleteList | Remove-Item
|
||||
$included = @{ }
|
||||
Get-ChildItem $target -Filter "*.dll" | Get-FileHash | ForEach-Object {
|
||||
$hash = $_.hash
|
||||
$filename = $_.Path | Split-Path -Leaf
|
||||
$included.Add([tuple]::Create($filename, $hash), $true)
|
||||
}
|
||||
Remove-Item -Path $target -Include "*.xml" -Recurse
|
||||
|
||||
$deleteList = Get-ChildItem $target\Plugins -Filter "*.dll" -Recurse |
|
||||
Select-Object Name, VersionInfo, Directory, @{ name = "hash"; expression = { (Get-FileHash $_.FullName) } } |
|
||||
Where-Object {
|
||||
$included.Contains([tuple]::Create($_.Name, $_.hash))
|
||||
}
|
||||
|
||||
$deleteList | ForEach-Object {
|
||||
Write-Host Deleting duplicated $_.Name with version $_.VersionInfo.FileVersion at location $_.Directory.FullName
|
||||
}
|
||||
$deleteList | Remove-Item -Path { $_.FullName }
|
||||
|
||||
Remove-Item -Path $target -Include "*.xml" -Recurse
|
||||
}
|
||||
|
||||
function Remove-CreateDumpExe ($path, $config) {
|
||||
function Remove-CreateDumpExe($path, $config)
|
||||
{
|
||||
$target = "$path\Output\$config"
|
||||
|
||||
$depjson = Get-Content $target\Flow.Launcher.deps.json -raw
|
||||
|
|
@ -56,12 +82,14 @@ function Remove-CreateDumpExe ($path, $config) {
|
|||
}
|
||||
|
||||
|
||||
function Validate-Directory ($output) {
|
||||
function Validate-Directory($output)
|
||||
{
|
||||
New-Item $output -ItemType Directory -Force
|
||||
}
|
||||
|
||||
|
||||
function Pack-Squirrel-Installer ($path, $version, $output) {
|
||||
function Pack-Squirrel-Installer($path, $version, $output)
|
||||
{
|
||||
# msbuild based installer generation is not working in appveyor, not sure why
|
||||
Write-Host "Begin pack squirrel installer"
|
||||
|
||||
|
|
@ -71,34 +99,20 @@ function Pack-Squirrel-Installer ($path, $version, $output) {
|
|||
Write-Host "Packing: $spec"
|
||||
Write-Host "Input path: $input"
|
||||
|
||||
# dotnet pack is not used because ran into issues, need to test installation and starting up if to use it.
|
||||
nuget pack $spec -Version $version -BasePath $input -OutputDirectory $output -Properties Configuration=Release
|
||||
|
||||
$nupkg = "$output\FlowLauncher.$version.nupkg"
|
||||
Write-Host "nupkg path: $nupkg"
|
||||
$icon = "$path\Flow.Launcher\Resources\app.ico"
|
||||
Write-Host "icon: $icon"
|
||||
# Squirrel.com: https://github.com/Squirrel/Squirrel.Windows/issues/369
|
||||
New-Alias Squirrel $env:USERPROFILE\.nuget\packages\squirrel.windows\1.5.2\tools\Squirrel.exe -Force
|
||||
# why we need Write-Output: https://github.com/Squirrel/Squirrel.Windows/issues/489#issuecomment-156039327
|
||||
# directory of releaseDir in squirrel can't be same as directory ($nupkg) in releasify
|
||||
$temp = "$output\Temp"
|
||||
|
||||
Squirrel --releasify $nupkg --releaseDir $temp --setupIcon $icon --no-msi | Write-Output
|
||||
Move-Item $temp\* $output -Force
|
||||
Remove-Item $temp
|
||||
$repoUrl = "https://github.com/Flow-Launcher/Prereleases"
|
||||
|
||||
$file = "$output\Flow-Launcher-Setup.exe"
|
||||
Write-Host "Filename: $file"
|
||||
|
||||
Move-Item "$output\Setup.exe" $file -Force
|
||||
|
||||
Write-Host "End pack squirrel installer"
|
||||
if ($channel -eq "stable")
|
||||
{
|
||||
$repoUrl = "https://github.com/Flow-Launcher/Flow.Launcher"
|
||||
}
|
||||
|
||||
vpk pack --packVersion $version --packDir $input --packId FlowLauncher --mainExe Flow.Launcher.exe --channel $channel
|
||||
}
|
||||
|
||||
function Publish-Self-Contained ($p) {
|
||||
function Publish-Self-Contained($p)
|
||||
{
|
||||
|
||||
$csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve
|
||||
$csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve
|
||||
$profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/Net7.0-SelfContained.pubxml" -Resolve
|
||||
|
||||
# we call dotnet publish on the main project.
|
||||
|
|
@ -106,31 +120,32 @@ function Publish-Self-Contained ($p) {
|
|||
dotnet publish -c Release $csproj /p:PublishProfile=$profile
|
||||
}
|
||||
|
||||
function Publish-Portable ($outputLocation, $version) {
|
||||
|
||||
function Publish-Portable($outputLocation, $version)
|
||||
{
|
||||
|
||||
& $outputLocation\Flow-Launcher-Setup.exe --silent | Out-Null
|
||||
mkdir "$env:LocalAppData\FlowLauncher\app-$version\UserData"
|
||||
Compress-Archive -Path $env:LocalAppData\FlowLauncher -DestinationPath $outputLocation\Flow-Launcher-Portable.zip
|
||||
}
|
||||
|
||||
function Main {
|
||||
function Main
|
||||
{
|
||||
$p = Build-Path
|
||||
$v = Build-Version
|
||||
Copy-Resources $p
|
||||
|
||||
if ($config -eq "Release"){
|
||||
|
||||
if ($config -eq "Release")
|
||||
{
|
||||
|
||||
Delete-Unused $p $config
|
||||
|
||||
Publish-Self-Contained $p
|
||||
|
||||
Remove-CreateDumpExe $p $config
|
||||
|
||||
$o = "$p\Output\Packages"
|
||||
Validate-Directory $o
|
||||
Pack-Squirrel-Installer $p $v $o
|
||||
|
||||
Publish-Portable $o $v
|
||||
# Publish-Portable $o $v
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
11
appveyor.yml
11
appveyor.yml
|
|
@ -7,6 +7,9 @@ init:
|
|||
if ($env:APPVEYOR_REPO_BRANCH -eq "dev")
|
||||
{
|
||||
$env:prereleaseTag = "{0}.{1}.{2}.{3}" -f $version.Major, $version.Minor, $version.Build, $version.Revision
|
||||
$env:channel = "prerelease"
|
||||
} else {
|
||||
$env:channel = "stable"
|
||||
}
|
||||
- sc config WSearch start= auto # Starts Windows Search service- Needed for running ExplorerTest
|
||||
- net start WSearch
|
||||
|
|
@ -40,12 +43,12 @@ artifacts:
|
|||
name: Plugin nupkg
|
||||
- path: 'Output\Packages\Flow-Launcher-*.exe'
|
||||
name: Squirrel Installer
|
||||
- path: Output\Packages\Flow-Launcher-Portable.zip
|
||||
- path: Release\Flow-Launcher-Portable.zip
|
||||
name: Portable Version
|
||||
- path: 'Output\Packages\FlowLauncher-*-full.nupkg'
|
||||
- path: 'Release\FlowLauncher-*-full.nupkg'
|
||||
name: Squirrel nupkg
|
||||
- path: 'Output\Packages\RELEASES'
|
||||
name: Squirrel RELEASES
|
||||
- path: 'Release\RELEASES*'
|
||||
name: Velopack RELEASES
|
||||
|
||||
deploy:
|
||||
- provider: NuGet
|
||||
|
|
|
|||
Loading…
Reference in a new issue