Skip to content

Commit

Permalink
Installer + auto update on startup
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bao-qian committed May 8, 2016
1 parent 810007e commit 644bd37
Show file tree
Hide file tree
Showing 15 changed files with 169 additions and 109 deletions.
4 changes: 2 additions & 2 deletions Deploy/build-release.ps1 → Deploy/binary_zip.ps1
Original file line number Diff line number Diff line change
@@ -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")
Expand Down
6 changes: 3 additions & 3 deletions Deploy/nuget.ps1
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions Deploy/squirrel_installer.ps1
Original file line number Diff line number Diff line change
@@ -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 changes: 16 additions & 0 deletions Deploy/wox.nuspec
Original file line number Diff line number Diff line change
@@ -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>
2 changes: 1 addition & 1 deletion Deploy/wox.plugin.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -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>
6 changes: 3 additions & 3 deletions SolutionAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
[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")]
1 change: 1 addition & 0 deletions Wox.Infrastructure/Wox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ public static class Wox
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";
}
}
4 changes: 2 additions & 2 deletions Wox/App.xaml
Original file line number Diff line number Diff line change
@@ -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>
Expand Down
97 changes: 58 additions & 39 deletions Wox/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -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();

Expand All @@ -47,53 +47,72 @@ protected override void OnStartup(StartupEventArgs e)
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();
});
}

private async void OnActivated(object sender, EventArgs e)
{
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 RegisterUnhandledException()
private void RegisterDispatcherUnhandledException()
{
// let exception throw as normal is better for Debug
// let exception throw as normal is better for Debug
DispatcherUnhandledException += ErrorReporting.DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
}

public void OnActivate(IList<string> args)
[Conditional("RELEASE")]
private static void RegisterAppDomainUnhandledException()
{
if (args.Count > 0 && args[0] == SingleInstance<App>.Restart)
{
API.CloseApp();
}
else
{
CommandArgsFactory.Execute(args);
}
// let exception throw as normal is better for Debug
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
}

private void OnExit(object sender, ExitEventArgs e)
public void OnActivate()
{
Save();
API.ShowApp();
}

private void OnSessionEnding(object sender, SessionEndingCancelEventArgs e)
private static void Save()
{
Save();
var vm = (MainViewModel)Window.DataContext;
vm.Save();
PluginManager.Save();
ImageLoader.Save();
_disposed = true;
}

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();
}
}
}
}
}
3 changes: 2 additions & 1 deletion Wox/CommandArgs/CommandArgsFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ static CommandArgsFactory()
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);
Expand Down
48 changes: 10 additions & 38 deletions Wox/Helper/SingleInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public static string[] CommandLineToArgvW(string cmdLine)

public interface ISingleInstanceApp
{
void OnActivate(IList<string> args);
void OnActivate();
}

/// <summary>
Expand Down Expand Up @@ -238,23 +238,10 @@ public static class SingleInstance<TApplication>
/// </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
Expand All @@ -266,10 +253,6 @@ public static IList<string> CommandLineArgs
/// <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;

Expand All @@ -283,17 +266,9 @@ public static bool InitializeAsFirstInstance( string uniqueName )
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;
}
}
Expand Down Expand Up @@ -398,7 +373,7 @@ private static void CreateRemoteService(string channelName)
/// <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);
Expand All @@ -414,7 +389,7 @@ private static void SignalFirstInstance(string channelName, IList<string> args)
{
// 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();
}
}

Expand All @@ -423,27 +398,25 @@ private static void SignalFirstInstance(string channelName, IList<string> args)
/// </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;
}

/// <summary>
/// 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)
{
return;
}

((TApplication)Application.Current).OnActivate(args);
((TApplication)Application.Current).OnActivate();
}

#endregion
Expand All @@ -459,14 +432,13 @@ private class IPCRemoteService : MarshalByRefObject
/// <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));
}
}

Expand Down
Loading

0 comments on commit 644bd37

Please sign in to comment.