diff --git a/Flow.Launcher.Core/Configuration/IPortable.cs b/Flow.Launcher.Core/Configuration/IPortable.cs
index e56b0188c..a741a0e9d 100644
--- a/Flow.Launcher.Core/Configuration/IPortable.cs
+++ b/Flow.Launcher.Core/Configuration/IPortable.cs
@@ -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();
}
-}
\ No newline at end of file
+}
diff --git a/Flow.Launcher.Core/Configuration/Portable.cs b/Flow.Launcher.Core/Configuration/Portable.cs
index b58154dcb..8b860b3a0 100644
--- a/Flow.Launcher.Core/Configuration/Portable.cs
+++ b/Flow.Launcher.Core/Configuration/Portable.cs
@@ -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
{
- ///
- /// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
- ///
- ///
- 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
///
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;
}
diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs
index 3a8e7ec7f..7fc50a02d 100644
--- a/Flow.Launcher.Core/Updater.cs
+++ b/Flow.Launcher.Core/Updater.cs
@@ -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)
diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
index 4137ca8d0..f25f9fe2a 100644
--- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
+++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
@@ -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);
+ }
+
+
///
/// 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
}
-
}
///
@@ -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
}
-
}
///
@@ -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);
}
-
+
///
/// Returns path ended with "\"
///
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index fbc7e7f31..2792fdfff 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -37,7 +37,11 @@ namespace Flow.Launcher
[STAThread]
public static void Main()
{
- VelopackApp.Build().Run();
+ VelopackApp.Build()
+ .WithAfterUpdateFastCallback(x =>
+ {
+ Updater.RecoverPortableData();
+ }).Run();
if (SingleInstance.InitializeAsFirstInstance(Unique))
{
diff --git a/Flow.Launcher/Helper/SingleInstance.cs b/Flow.Launcher/Helper/SingleInstance.cs
index b5cd67a00..b0b8e84b2 100644
--- a/Flow.Launcher/Helper/SingleInstance.cs
+++ b/Flow.Launcher/Helper/SingleInstance.cs
@@ -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;
+
-
///
/// 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
/// True if this is the first instance of the application.
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
/// Cancellation token
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;
}
///
@@ -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);
}
diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs
index 00e7df3d0..6d5d4e1ba 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -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;
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs
index 792891ad1..7a7496ece 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs
@@ -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
/// overwrite
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)
diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1
index 1757ed99e..b1f566abf 100644
--- a/Scripts/post_build.ps1
+++ b/Scripts/post_build.ps1
@@ -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
}
}
diff --git a/appveyor.yml b/appveyor.yml
index b84230c43..6a96f88d8 100644
--- a/appveyor.yml
+++ b/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