Installer + auto update on startup

1. installer
2. auto check update on startup
3. auto start on next startup
4. remove command line arguments which breaks squirrel
5. auto generate installer on continue integration
This commit is contained in:
bao-qian 2016-05-07 22:44:38 +01:00
parent 192e4b8877
commit e0b9a81c9b
15 changed files with 171 additions and 111 deletions

View File

@ -1,8 +1,8 @@
$sourceDirectoryName = $env:APPVEYOR_BUILD_FOLDER + "\Output\Release"
$fileName = $env:APPVEYOR_BUILD_FOLDER + "\Wox-$env:APPVEYOR_BUILD_VERSION.zip"
$current_path = Convert-Path .
Write-Host "Current path: " + $current_path
$currentPath = Convert-Path .
Write-Host "Current path: " + $currentPath
Write-Host "Target path: " + $sourceDirectoryName
[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem")

View File

@ -1,7 +1,7 @@
$path = $env:APPVEYOR_BUILD_FOLDER + "\Deploy\wox.plugin.nuspec"
$current_path = Convert-Path .
Write-Host "Current path: " + $current_path
Write-Host "Target path: " + $path
$currentPath = Convert-Path .
Write-Host "Current path:" + $currentPath
Write-Host "nuspec path:" + $path
& nuget pack $path -Version $env:APPVEYOR_BUILD_VERSION

View File

@ -0,0 +1,15 @@
$currentPath = Convert-Path .
Write-Host "Current path: " + $currentPath
$path = $env:APPVEYOR_BUILD_FOLDER + "\Deploy\wox.nuspec"
Write-Host "nuspec path: " + $path
& nuget.exe pack $path -Version $env:APPVEYOR_BUILD_VERSION -Properties Configuration=Release
$nupkgPath = $env:APPVEYOR_BUILD_FOLDER + "\Wox." + $env:APPVEYOR_BUILD_VERSION + ".nupkg"
Write-Host "nupkg path: " + $nupkgPath
# must use Squirrel.com, Squirrel.exe will produce nothing
$squirrelPath = $env:APPVEYOR_BUILD_FOLDER + "\packages\squirrel*\tools\Squirrel.com"
Write-Host "squirrel path: " + $squirrelPath
$iconPath = $env:APPVEYOR_BUILD_FOLDER + "\Wox\Resources\app.ico"
& $squirrelPath --releasify $nupkgPath --setupIcon $iconPath --no-msi

16
Deploy/wox.nuspec Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Wox</id>
<title>Wox</title>
<version>$version$</version>
<authors>happlebao</authors>
<projectUrl>https://github.com/Wox-launcher/Wox</projectUrl>
<iconUrl>https://raw.githubusercontent.com/Wox-launcher/Wox/master/Wox/Images/app.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Wox - a launcher for windows</description>
</metadata>
<files>
<file src="..\Output\Release\**\*.*" target="lib\net45\" exclude="*.nupkg;*.vshost.*"/>
</files>
</package>

View File

@ -11,6 +11,6 @@
<tags>wox</tags>
</metadata>
<files>
<file src="..\Output\Release\Wox.Plugin.dll" target="lib\net35" />
<file src="..\Output\Release\Wox.Plugin.dll" target="lib\net452" />
</files>
</package>

View File

@ -9,12 +9,12 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("Release build, https://github.com/Wox-launcher/Wox")]
#endif
[assembly: AssemblyCompany("Wox-launcher")]
[assembly: AssemblyCompany("Wox")]
[assembly: AssemblyProduct("Wox")]
[assembly: AssemblyCopyright("The MIT License (MIT)")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2-beta.2")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]

View File

@ -15,5 +15,6 @@ namespace Wox.Infrastructure
public static readonly string UserDirectory = Path.Combine(DataPath, Plugins);
public static readonly string PreinstalledDirectory = Path.Combine(ProgramPath, Plugins);
public static readonly string SettingsPath = Path.Combine(DataPath, Settings);
public const string Github = "https://github.com/Wox-launcher/Wox";
}
}

View File

@ -1,8 +1,8 @@
<Application x:Class="Wox.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Exit="OnExit"
SessionEnding="OnSessionEnding">
Startup="OnStartup"
Activated="OnActivated">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>

View File

@ -1,43 +1,43 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Wox.CommandArgs;
using Squirrel;
using Wox.Core.Plugin;
using Wox.Helper;
using Wox.Infrastructure.Image;
using Wox.ViewModel;
using Stopwatch = Wox.Infrastructure.Stopwatch;
using Wox.Infrastructure.Logger;
namespace Wox
{
public partial class App : ISingleInstanceApp
public partial class App : ISingleInstanceApp, IDisposable
{
private const string Unique = "Wox_Unique_Application_Mutex";
public static MainWindow Window { get; private set; }
public static PublicAPIInstance API { get; private set; }
private bool _saved;
private static bool _disposed;
public static UpdateManager Updater;
[STAThread]
public static void Main()
{
RegisterAppDomainUnhandledException();
if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
{
var application = new App();
application.InitializeComponent();
application.Run();
SingleInstance<App>.Cleanup();
using (var application = new App())
{
application.InitializeComponent();
application.Run();
}
}
}
protected override void OnStartup(StartupEventArgs e)
private void OnStartup(object sender, StartupEventArgs e)
{
Stopwatch.Debug("Startup Time", () =>
{
base.OnStartup(e);
RegisterUnhandledException();
RegisterDispatcherUnhandledException();
ImageLoader.PreloadImages();
@ -47,53 +47,72 @@ namespace Wox
PluginManager.InitializePlugins(API, pluginsSettings);
Window = new MainWindow(mainVM._settings, mainVM);
NotifyIconManager notifyIconManager = new NotifyIconManager(API);
CommandArgsFactory.Execute(e.Args.ToList());
var _notifyIconManager = new NotifyIconManager(API);
RegisterExitEvents();
});
}
[Conditional("RELEASE")]
private void RegisterUnhandledException()
private async void OnActivated(object sender, EventArgs e)
{
// let exception throw as normal is better for Debug
try
{
using (Updater = await UpdateManager.GitHubUpdateManager(Infrastructure.Wox.Github, prerelease: true))
{
await Updater.UpdateApp();
}
}
catch (Exception exception)
{
Log.Error(exception);
}
}
private void RegisterExitEvents()
{
AppDomain.CurrentDomain.ProcessExit += (s, e) => Dispose();
Current.Exit += (s, e) => Dispose();
Current.SessionEnding += (s, e) => Dispose();
}
[Conditional("RELEASE")]
private void RegisterDispatcherUnhandledException()
{
// let exception throw as normal is better for Debug
DispatcherUnhandledException += ErrorReporting.DispatcherUnhandledException;
}
[Conditional("RELEASE")]
private static void RegisterAppDomainUnhandledException()
{
// let exception throw as normal is better for Debug
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
}
public void OnActivate(IList<string> args)
public void OnActivate()
{
if (args.Count > 0 && args[0] == SingleInstance<App>.Restart)
{
API.CloseApp();
}
else
{
CommandArgsFactory.Execute(args);
}
API.ShowApp();
}
private void OnExit(object sender, ExitEventArgs e)
private static void Save()
{
Save();
var vm = (MainViewModel)Window.DataContext;
vm.Save();
PluginManager.Save();
ImageLoader.Save();
_disposed = true;
}
private void OnSessionEnding(object sender, SessionEndingCancelEventArgs e)
{
Save();
}
private void Save()
public void Dispose()
{
// if sessionending is called, exit proverbially be called when log off / shutdown
// but if sessionending is not called, exit won't be called when log off / shutdown
if (!_saved)
if (!_disposed)
{
var vm = (MainViewModel) Window.DataContext;
vm.Save();
PluginManager.Save();
ImageLoader.Save();
_saved = true;
Save();
Updater?.Dispose();
SingleInstance<App>.Cleanup();
}
}
}
}
}

View File

@ -22,7 +22,8 @@ namespace Wox.CommandArgs
public static void Execute(IList<string> args)
{
// todo restart command line args?
if (args.Count > 0 && args[0] != SingleInstance<App>.Restart)
//if (args.Count > 0 && args[0] != SingleInstance<App>.Restart)
if (args.Count > 0)
{
string command = args[0];
ICommandArg cmd = commandArgs.FirstOrDefault(o => o.Command.ToLower() == command);

View File

@ -186,7 +186,7 @@ namespace Wox.Helper
public interface ISingleInstanceApp
{
void OnActivate(IList<string> args);
void OnActivate();
}
/// <summary>
@ -238,23 +238,10 @@ namespace Wox.Helper
/// </summary>
private static IpcServerChannel channel;
/// <summary>
/// List of command line arguments for the application.
/// </summary>
private static IList<string> commandLineArgs;
#endregion
#region Public Properties
/// <summary>
/// Gets list of command line arguments for the application.
/// </summary>
public static IList<string> CommandLineArgs
{
get { return commandLineArgs; }
}
#endregion
#region Public Methods
@ -266,10 +253,6 @@ namespace Wox.Helper
/// <returns>True if this is the first instance of the application.</returns>
public static bool InitializeAsFirstInstance( string uniqueName )
{
commandLineArgs = GetCommandLineArgs(uniqueName);
//remove execute path itself
commandLineArgs.RemoveAt(0);
// Build unique application Id and the IPC channel name.
string applicationIdentifier = uniqueName + Environment.UserName;
@ -283,17 +266,9 @@ namespace Wox.Helper
CreateRemoteService(channelName);
return true;
}
// Restart
else if (commandLineArgs.Count > 0 && commandLineArgs[0] == Restart)
{
SignalFirstInstance(channelName, commandLineArgs);
singleInstanceMutex.WaitOne(TimeSpan.FromSeconds(10));
CreateRemoteService(channelName);
return true;
}
else
{
SignalFirstInstance(channelName, commandLineArgs);
SignalFirstInstance(channelName);
return false;
}
}
@ -398,7 +373,7 @@ namespace Wox.Helper
/// <param name="args">
/// Command line arguments for the second instance, passed to the first instance to take appropriate action.
/// </param>
private static void SignalFirstInstance(string channelName, IList<string> args)
private static void SignalFirstInstance(string channelName)
{
IpcClientChannel secondInstanceChannel = new IpcClientChannel();
ChannelServices.RegisterChannel(secondInstanceChannel, true);
@ -414,7 +389,7 @@ namespace Wox.Helper
{
// Invoke a method of the remote service exposed by the first instance passing on the command line
// arguments and causing the first instance to activate itself
firstInstanceRemoteServiceReference.InvokeFirstInstance(args);
firstInstanceRemoteServiceReference.InvokeFirstInstance();
}
}
@ -423,11 +398,9 @@ namespace Wox.Helper
/// </summary>
/// <param name="arg">Callback argument.</param>
/// <returns>Always null.</returns>
private static object ActivateFirstInstanceCallback(object arg)
private static object ActivateFirstInstanceCallback(object o)
{
// Get command line args to be passed to first instance
IList<string> args = arg as IList<string>;
ActivateFirstInstance(args);
ActivateFirstInstance();
return null;
}
@ -435,7 +408,7 @@ namespace Wox.Helper
/// Activates the first instance of the application with arguments from a second instance.
/// </summary>
/// <param name="args">List of arguments to supply the first instance of the application.</param>
private static void ActivateFirstInstance(IList<string> args)
private static void ActivateFirstInstance()
{
// Set main window state and process command line args
if (Application.Current == null)
@ -443,7 +416,7 @@ namespace Wox.Helper
return;
}
((TApplication)Application.Current).OnActivate(args);
((TApplication)Application.Current).OnActivate();
}
#endregion
@ -459,14 +432,13 @@ namespace Wox.Helper
/// <summary>
/// Activates the first instance of the application.
/// </summary>
/// <param name="args">List of arguments to pass to the first instance.</param>
public void InvokeFirstInstance(IList<string> args)
public void InvokeFirstInstance()
{
if (Application.Current != null)
{
// Do an asynchronous call to ActivateFirstInstance function
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Normal, new DispatcherOperationCallback(ActivateFirstInstanceCallback), args);
DispatcherPriority.Normal, new DispatcherOperationCallback(ActivateFirstInstanceCallback));
}
}

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using System.Windows;
using NHotkey;
using NHotkey.Wpf;
using Squirrel;
using Wox.Core.Plugin;
using Wox.Core.Resource;
using Wox.Core.UserSettings;
@ -67,12 +68,7 @@ namespace Wox
public void RestarApp()
{
ProcessStartInfo info = new ProcessStartInfo
{
FileName = Application.ResourceAssembly.Location,
Arguments = SingleInstance<App>.Restart
};
Process.Start(info);
UpdateManager.RestartApp();
}
public void HideApp()

View File

@ -60,6 +60,18 @@
<StartupObject>Wox.App</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="DeltaCompressionDotNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.0.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.MsDelta.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.PatchApi.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Exceptionless, Version=1.5.2121.0, Culture=neutral, PublicKeyToken=fc181f0a46f65747, processorArchitecture=MSIL">
<HintPath>..\packages\Exceptionless.1.5.2121\lib\net45\Exceptionless.dll</HintPath>
<Private>True</Private>
@ -68,16 +80,28 @@
<HintPath>..\packages\Exceptionless.1.5.2121\lib\net45\Exceptionless.Models.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\squirrel.windows.1.4.0\lib\Net45\ICSharpCode.SharpZipLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="JetBrains.Annotations, Version=10.1.4.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
<HintPath>..\packages\JetBrains.Annotations.10.1.4\lib\net20\JetBrains.Annotations.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MarkdownSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll</HintPath>
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@ -92,8 +116,20 @@
<HintPath>..\packages\NHotkey.Wpf.1.2.1\lib\net35\NHotkey.Wpf.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\squirrel.windows.1.4.0\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PresentationUI, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="ReachFramework" />
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Squirrel, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\squirrel.windows.1.4.0\lib\Net45\Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />

View File

@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DeltaCompressionDotNet" version="1.0.0" targetFramework="net452" />
<package id="Exceptionless" version="1.5.2121" targetFramework="net452" />
<package id="InputSimulator" version="1.0.4.0" targetFramework="net452" />
<package id="JetBrains.Annotations" version="10.1.4" targetFramework="net452" />
<package id="MarkdownSharp" version="1.13.0.0" targetFramework="net452" />
<package id="Mono.Cecil" version="0.9.6.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="net452" />
<package id="NHotkey" version="1.2.1" targetFramework="net452" />
<package id="NHotkey.Wpf" version="1.2.1" targetFramework="net452" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net452" />
<package id="Splat" version="1.6.2" targetFramework="net452" />
<package id="squirrel.windows" version="1.4.0" targetFramework="net452" />
<package id="System.Runtime" version="4.0.0" targetFramework="net452" />
</packages>

View File

@ -16,16 +16,17 @@ after_test:
- ps: >-
.\Deploy\nuget.ps1
.\Deploy\build-release.ps1
.\Deploy\binary_zip.ps1
.\Deploy\squirrel_installer.ps1
artifacts:
- path: 'Wox-*.zip'
name: release_binary
name: zipped_binary
- path: '*.nupkg'
name: nuget_package
deploy:
- provider: NuGet
api_key:
secure: yybUOFgBuGVpbmOVZxsurC8OpkClzt9dR+/54WpMWcq6b6oyMatciaelRPnXsjRn
artifact: nuget_package
on:
branch: api
- path: '\Releases\*.exe'
name: installer
- path: '\Releases\*.nupkg'
name: installer
- path: 'Releases\RELEASES'
name: installer