migrate to velopack

This commit is contained in:
Hongtao Zhang 2024-03-24 13:41:07 -05:00
parent 1cc8b9dfe8
commit 3d6782ca30
10 changed files with 200 additions and 218 deletions

View file

@ -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();
}
}
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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>

View file

@ -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))
{

View file

@ -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);
}

View file

@ -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;

View file

@ -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)

View file

@ -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
}
}

View file

@ -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