public WixUiBootstrapper( IWiXEvents wixEvents, TinyIoCContainer testKernel = null, IRoutingState router = null, IFileSystemFactory fileSystem = null, string currentAssemblyDir = null, string targetRootDirectory = null) { Kernel = testKernel ?? createDefaultKernel(); this.fileSystem = fileSystem ?? AnonFileSystem.Default; this.currentAssemblyDir = currentAssemblyDir ?? Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); RxApp.ConfigureServiceLocator( (type, contract) => { this.Log().Debug("Resolving type '{0}' with contract '{1}'", type, contract); return String.IsNullOrEmpty(contract) ? Kernel.Resolve(type) : Kernel.Resolve(type, contract); }, (type, contract) => Kernel.ResolveAll(type, true), (c, t, s) => { this.Log().Debug("Registering type '{0}' for interface '{1}' and contract '{2}'", c, t, s); if (String.IsNullOrEmpty(s)) { Kernel.Register(t, c, Guid.NewGuid().ToString()); } else { Kernel.Register(t, c, s); } }); RxRouting.ViewModelToViewFunc = findViewClassNameForViewModelName; Kernel.Register<IWixUiBootstrapper>(this); Kernel.Register<IScreen>(this); Kernel.Register(wixEvents); Router = router ?? new RoutingState(); WiXEvents = wixEvents; _BundledRelease = new Lazy<ReleaseEntry>(readBundledReleasesFile); registerExtensionDlls(Kernel); UserError.RegisterHandler(ex => { this.Log().ErrorException("Something unexpected happened", ex.InnerException); if (wixEvents.DisplayMode != Display.Full) { this.Log().Error(ex.ErrorMessage); wixEvents.ShouldQuit(); } var errorVm = RxApp.GetService<IErrorViewModel>(); errorVm.Error = ex; errorVm.Shutdown.Subscribe(_ => wixEvents.ShouldQuit()); errorVm.OpenLogsFolder.Subscribe(_ => openLogsFolder()); RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(errorVm)); return Observable.Return(RecoveryOptionResult.CancelOperation); }); bundledPackageMetadata = new Lazy<IPackage>(openBundledPackage); wixEvents.DetectPackageCompleteObs.Subscribe(eventArgs => { this.Log().Info("DetectPackageCompleteObs: got id: '{0}', state: '{1}', status: '{2}'", eventArgs.PackageId, eventArgs.State, eventArgs.Status); var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } // we now have multiple applications in the chain // only run this code after the last entry in the chain if (eventArgs.PackageId != "UserApplicationId") return; if (wixEvents.Action == LaunchAction.Uninstall) { if (wixEvents.DisplayMode != Display.Full) { this.Log().Info("Squirrel is doing a silent uninstall! Sneaky!"); wixEvents.Engine.Plan(LaunchAction.Uninstall); return; } this.Log().Info("Squirrel is doing an uninstall! Sadface!"); var uninstallVm = RxApp.GetService<IUninstallingViewModel>(); Router.Navigate.Execute(uninstallVm); wixEvents.Engine.Plan(LaunchAction.Uninstall); return; } // TODO: If the app is already installed, run it and bail // If Display is silent, we should just exit here. if (wixEvents.Action == LaunchAction.Install) { if (wixEvents.DisplayMode != Display.Full) { this.Log().Info("Squirrel is doing a silent install! Sneaky!"); wixEvents.Engine.Plan(LaunchAction.Install); return; } this.Log().Info("We are doing an UI install! Huzzah!"); var welcomeVm = RxApp.GetService<IWelcomeViewModel>(); welcomeVm.PackageMetadata = bundledPackageMetadata.Value; welcomeVm.ShouldProceed.Subscribe(_ => wixEvents.Engine.Plan(LaunchAction.Install)); // NB: WiX runs a "Main thread" that all of these events // come back on, and a "UI thread" where it actually runs // the WPF window. Gotta proxy to the UI thread. RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(welcomeVm)); } }); var executablesToStart = Enumerable.Empty<string>(); wixEvents.PlanCompleteObs.Subscribe(eventArgs => { this.Log().Info("PlanCompleteObs: got status: '{0}'", eventArgs.Status); var installManager = new InstallManager(BundledRelease, targetRootDirectory); var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Action == LaunchAction.Uninstall) { var task = installManager.ExecuteUninstall(BundledRelease.Version); task.Subscribe( _ => wixEvents.Engine.Apply(wixEvents.MainWindowHwnd), ex => UserError.Throw(new UserError("Failed to uninstall", ex.Message, innerException: ex))); // the installer can close before the uninstall is done // which means the UpdateManager is not disposed correctly // which means an error is thrown in the destructor // // let's wait for it to finish // // oh, and .Wait() is unnecesary here // because the subscriber handles an exception var result = task.FirstOrDefault(); return; } IObserver<int> progress = null; if (wixEvents.DisplayMode == Display.Full) { var installingVm = RxApp.GetService<IInstallingViewModel>(); progress = installingVm.ProgressValue; installingVm.PackageMetadata = bundledPackageMetadata.Value; RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(installingVm)); } installManager.ExecuteInstall(this.currentAssemblyDir, bundledPackageMetadata.Value, progress).Subscribe( toStart => { executablesToStart = toStart ?? executablesToStart; wixEvents.Engine.Apply(wixEvents.MainWindowHwnd); }, ex => UserError.Throw("Failed to install application", ex)); }); wixEvents.ApplyCompleteObs.Subscribe(eventArgs => { this.Log().Info("ApplyCompleteObs: got restart: '{0}', result: '{1}', status: '{2}'", eventArgs.Restart, eventArgs.Result, eventArgs.Status); var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.DisplayMode == Display.Full && wixEvents.Action == LaunchAction.Install) { var processFactory = Kernel.Resolve<IProcessFactory>(); foreach (var path in executablesToStart) { processFactory.Start(path); } } wixEvents.ShouldQuit(); }); wixEvents.ErrorObs.Subscribe( eventArgs => { this.Log().Info("ErrorObs: got id: '{0}', result: '{1}', code: '{2}'", eventArgs.PackageId, eventArgs.Result, eventArgs.ErrorCode); UserError.Throw("An installation error has occurred: " + eventArgs.ErrorMessage); }); wixEvents.Engine.Detect(); }
public WixUiBootstrapper(IWiXEvents wixEvents, TinyIoCContainer testKernel = null, IRoutingState router = null, IFileSystemFactory fileSystem = null, string currentAssemblyDir = null) { Kernel = testKernel ?? createDefaultKernel(); this.fileSystem = fileSystem ?? AnonFileSystem.Default; this.currentAssemblyDir = currentAssemblyDir ?? Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); RxApp.ConfigureServiceLocator( (type, contract) => { this.Log().Info("Resolving type '{0}' with contract '{1}'", type, contract); return(String.IsNullOrEmpty(contract) ? Kernel.Resolve(type) : Kernel.Resolve(type, contract)); }, (type, contract) => Kernel.ResolveAll(type, true), (c, t, s) => { this.Log().Info("Registering type '{0}' for interface '{1}' and contract '{2}'", c, t, s); if (String.IsNullOrEmpty(s)) { Kernel.Register(t, c, Guid.NewGuid().ToString()); } else { Kernel.Register(t, c, s); } }); RxRouting.ViewModelToViewFunc = findViewClassNameForViewModelName; Kernel.Register <IWixUiBootstrapper>(this); Kernel.Register <IScreen>(this); Kernel.Register(wixEvents); Router = router ?? new RoutingState(); WiXEvents = wixEvents; _BundledRelease = new Lazy <ReleaseEntry>(readBundledReleasesFile); registerExtensionDlls(Kernel); UserError.RegisterHandler(ex => { this.Log().ErrorException("Something unexpected happened", ex.InnerException); if (wixEvents.DisplayMode != Display.Full) { this.Log().Error(ex.ErrorMessage); wixEvents.ShouldQuit(); } var errorVm = RxApp.GetService <IErrorViewModel>(); errorVm.Error = ex; errorVm.Shutdown.Subscribe(_ => wixEvents.ShouldQuit()); errorVm.OpenLogsFolder.Subscribe(_ => openLogsFolder()); RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(errorVm)); return(Observable.Return(RecoveryOptionResult.CancelOperation)); }); bundledPackageMetadata = new Lazy <IPackage>(openBundledPackage); wixEvents.DetectPackageCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Action == LaunchAction.Uninstall) { this.Log().Info("Shimmer is doing an uninstall! Sadface!"); var uninstallVm = RxApp.GetService <IUninstallingViewModel>(); Router.Navigate.Execute(uninstallVm); wixEvents.Engine.Plan(LaunchAction.Uninstall); return; } // TODO: If the app is already installed, run it and bail // If Display is silent, we should just exit here. if (wixEvents.Action == LaunchAction.Install) { if (wixEvents.DisplayMode != Display.Full) { this.Log().Info("Shimmer is doing a silent install! Sneaky!"); wixEvents.Engine.Plan(LaunchAction.Install); return; } this.Log().Info("We are doing an UI install! Huzzah!"); var welcomeVm = RxApp.GetService <IWelcomeViewModel>(); welcomeVm.PackageMetadata = bundledPackageMetadata.Value; welcomeVm.ShouldProceed.Subscribe(_ => wixEvents.Engine.Plan(LaunchAction.Install)); // NB: WiX runs a "Main thread" that all of these events // come back on, and a "UI thread" where it actually runs // the WPF window. Gotta proxy to the UI thread. RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(welcomeVm)); } }); var executablesToStart = Enumerable.Empty <string>(); wixEvents.PlanCompleteObs.Subscribe(eventArgs => { var installManager = new InstallManager(BundledRelease); var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Action == LaunchAction.Uninstall) { installManager.ExecuteUninstall().Subscribe( _ => wixEvents.Engine.Apply(wixEvents.MainWindowHwnd), ex => UserError.Throw(new UserError("Failed to uninstall", ex.Message, innerException: ex))); return; } IObserver <int> progress = null; if (wixEvents.DisplayMode == Display.Full) { var installingVm = RxApp.GetService <IInstallingViewModel>(); progress = installingVm.ProgressValue; installingVm.PackageMetadata = bundledPackageMetadata.Value; RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(installingVm)); } installManager.ExecuteInstall(this.currentAssemblyDir, bundledPackageMetadata.Value, progress).Subscribe( toStart => { executablesToStart = toStart ?? executablesToStart; wixEvents.Engine.Apply(wixEvents.MainWindowHwnd); }, ex => UserError.Throw("Failed to install application", ex)); }); wixEvents.ApplyCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.DisplayMode == Display.Full && wixEvents.Action == LaunchAction.Install) { foreach (var path in executablesToStart) { Process.Start(path); } } wixEvents.ShouldQuit(); }); wixEvents.ErrorObs.Subscribe(eventArgs => UserError.Throw("An installation error has occurred: " + eventArgs.ErrorMessage)); wixEvents.Engine.Detect(); }
public WixUiBootstrapper(IWiXEvents wixEvents, TinyIoCContainer testKernel = null, IRoutingState router = null) { Kernel = testKernel ?? createDefaultKernel(); Kernel.Register<IWixUiBootstrapper>(this).AsSingleton(); Kernel.Register<IScreen>(this); Kernel.Register(wixEvents); Router = router ?? new RoutingState(); WiXEvents = wixEvents; _BundledRelease = new Lazy<ReleaseEntry>(readBundledReleasesFile); registerExtensionDlls(Kernel); RxApp.ConfigureServiceLocator( (type, contract) => Kernel.Resolve(type, contract), (type, contract) => Kernel.ResolveAll(type), (c, t, s) => Kernel.Register(t, c, s)); UserError.RegisterHandler(ex => { if (wixEvents.Command.Display != Display.Full) { this.Log().Error(ex.ErrorMessage); wixEvents.ShouldQuit(); } var errorVm = RxApp.GetService<IErrorViewModel>(); errorVm.Error = ex; Router.Navigate.Execute(errorVm); return Observable.Return(RecoveryOptionResult.CancelOperation); }); var bundledPackageMetadata = openBundledPackage(); wixEvents.DetectPackageCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } // TODO: If the app is already installed, run it and bail if (wixEvents.Command.Action == LaunchAction.Uninstall) { var updateManager = new UpdateManager("http://lol", BundledRelease.PackageName, FrameworkVersion.Net40); var updateLock = updateManager.AcquireUpdateLock(); updateManager.FullUninstall() .ObserveOn(RxApp.DeferredScheduler) .Log(this, "Failed uninstall") .Finally(updateLock.Dispose) .Subscribe( _ => wixEvents.Engine.Plan(LaunchAction.Uninstall), ex => UserError.Throw("Failed to uninstall application", ex), () => wixEvents.ShouldQuit()); return; } if (wixEvents.Command.Action == LaunchAction.Install) { if (wixEvents.Command.Display != Display.Full) { wixEvents.Engine.Plan(LaunchAction.Install); return; } var welcomeVm = RxApp.GetService<IWelcomeViewModel>(); welcomeVm.PackageMetadata = bundledPackageMetadata; welcomeVm.ShouldProceed.Subscribe(_ => wixEvents.Engine.Plan(LaunchAction.Install)); Router.Navigate.Execute(welcomeVm); } }); wixEvents.PlanCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Command.Action != LaunchAction.Install) { wixEvents.Engine.Apply(wixEvents.MainWindowHwnd); return; } // NB: Create a dummy subject to receive progress if we're in silent mode IObserver<int> progress = new Subject<int>(); if (wixEvents.Command.Display == Display.Full) { var installingVm = RxApp.GetService<IInstallingViewModel>(); progress = installingVm.ProgressValue; installingVm.PackageMetadata = bundledPackageMetadata; Router.Navigate.Execute(installingVm); } // NB: This bit of code is a bit clever. The binaries that WiX // has installed *itself* meets the qualifications for being a // Shimmer update directory (a RELEASES file and the corresponding // NuGet packages). // // So, in order to reuse some code and not write the same things // twice we're going to "Eigenupdate" from our own directory; // UpdateManager will operate in bootstrap mode and create a // local directory for us. // // Then, we create a *new* UpdateManager whose target is the normal // update URL - we can then apply delta updates against the bundled // NuGet package to get up to vCurrent. The reason we go through // this rigamarole is so that developers don't have to rebuild the // installer as often (never, technically). var fxVersion = determineFxVersionFromPackage(bundledPackageMetadata); var eigenUpdater = new UpdateManager(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), BundledRelease.PackageName, fxVersion); var eigenLock = eigenUpdater.AcquireUpdateLock(); var eigenUpdateProgress = eigenUpdater.CheckForUpdate() .SelectMany(x => eigenUpdater.DownloadReleases(x.ReleasesToApply)) .Finally(eigenLock.Dispose) .Select(x => x / 2) .Multicast(new Subject<int>()); eigenUpdateProgress.Subscribe(progress); eigenUpdateProgress.Connect(); var realUpdateProgress = eigenUpdateProgress.TakeLast(1) .SelectMany(_ => { var realUpdateManager = new UpdateManager(bundledPackageMetadata.ProjectUrl.ToString(), BundledRelease.PackageName, fxVersion); return realUpdateManager.CheckForUpdate() .SelectMany(updateInfo => { return Observable.Concat( realUpdateManager.DownloadReleases(updateInfo.ReleasesToApply).Select(x => x * 0.75), realUpdateManager.ApplyReleases(updateInfo).Select(x => x * 0.25 + 75)) .Select(x => (int)x); }).LoggedCatch(this, Observable.Return(100), "Failed to update to latest remote version"); }) .Select(x => x / 2 + 50) .Multicast(new Subject<int>()); realUpdateProgress.Subscribe(progress); realUpdateProgress.Connect(); realUpdateProgress .TakeLast(1) .ObserveOn(RxApp.DeferredScheduler) .Subscribe( _ => wixEvents.Engine.Apply(wixEvents.MainWindowHwnd), ex => UserError.Throw("Failed to install application", ex)); }); wixEvents.ApplyCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Command.Display != Display.Full) { wixEvents.ShouldQuit(); } // TODO: Figure out what the "main app" is and run it }); wixEvents.ErrorObs.Subscribe(eventArgs => UserError.Throw("An installation error has occurred: " + eventArgs.ErrorMessage)); }
public WixUiBootstrapper(IWiXEvents wixEvents, TinyIoCContainer testKernel = null, IRoutingState router = null, IFileSystemFactory fileSystem = null, string currentAssemblyDir = null) { Kernel = testKernel ?? createDefaultKernel(); this.fileSystem = fileSystem ?? AnonFileSystem.Default; this.currentAssemblyDir = currentAssemblyDir ?? Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); RxApp.ConfigureServiceLocator( (type, contract) => String.IsNullOrEmpty(contract) ? Kernel.Resolve(type) : Kernel.Resolve(type, contract), (type, contract) => Kernel.ResolveAll(type, true), (c, t, s) => { if (String.IsNullOrEmpty(s)) { Kernel.Register(t, c, Guid.NewGuid().ToString()); } else { Kernel.Register(t, c, s); } }); RxRouting.ViewModelToViewFunc = findViewClassNameForViewModelName; Kernel.Register<IWixUiBootstrapper>(this); Kernel.Register<IScreen>(this); Kernel.Register(wixEvents); Router = router ?? new RoutingState(); WiXEvents = wixEvents; _BundledRelease = new Lazy<ReleaseEntry>(readBundledReleasesFile); registerExtensionDlls(Kernel); UserError.RegisterHandler(ex => { if (wixEvents.DisplayMode != Display.Full) { this.Log().Error(ex.ErrorMessage); wixEvents.ShouldQuit(); } var errorVm = RxApp.GetService<IErrorViewModel>(); errorVm.Error = ex; RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(errorVm)); return Observable.Return(RecoveryOptionResult.CancelOperation); }); bundledPackageMetadata = new Lazy<IPackage>(openBundledPackage); wixEvents.DetectPackageCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Action == LaunchAction.Uninstall) { var uninstallVm = RxApp.GetService<IUninstallingViewModel>(); Router.Navigate.Execute(uninstallVm); wixEvents.Engine.Plan(LaunchAction.Uninstall); return; } // TODO: If the app is already installed, run it and bail // If Display is silent, we should just exit here. if (wixEvents.Action == LaunchAction.Install) { if (wixEvents.DisplayMode != Display.Full) { wixEvents.Engine.Plan(LaunchAction.Install); return; } var welcomeVm = RxApp.GetService<IWelcomeViewModel>(); welcomeVm.PackageMetadata = bundledPackageMetadata.Value; welcomeVm.ShouldProceed.Subscribe(_ => wixEvents.Engine.Plan(LaunchAction.Install)); // NB: WiX runs a "Main thread" that all of these events // come back on, and a "UI thread" where it actually runs // the WPF window. Gotta proxy to the UI thread. RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(welcomeVm)); } }); var executablesToStart = Enumerable.Empty<string>(); wixEvents.PlanCompleteObs.Subscribe(eventArgs => { var installManager = new InstallManager(BundledRelease); var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Action == LaunchAction.Uninstall) { installManager.ExecuteUninstall().Subscribe( _ => wixEvents.Engine.Apply(wixEvents.MainWindowHwnd), ex => UserError.Throw(new UserError("Failed to uninstall", ex.Message, innerException: ex))); return; } IObserver<int> progress = null; if (wixEvents.DisplayMode == Display.Full) { var installingVm = RxApp.GetService<IInstallingViewModel>(); progress = installingVm.ProgressValue; installingVm.PackageMetadata = bundledPackageMetadata.Value; RxApp.DeferredScheduler.Schedule(() => Router.Navigate.Execute(installingVm)); } installManager.ExecuteInstall(this.currentAssemblyDir, bundledPackageMetadata.Value, progress).Subscribe( toStart => { executablesToStart = toStart ?? executablesToStart; wixEvents.Engine.Apply(wixEvents.MainWindowHwnd); }, ex => UserError.Throw("Failed to install application", ex)); }); wixEvents.ApplyCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.DisplayMode == Display.Full && wixEvents.Action == LaunchAction.Install) { foreach (var path in executablesToStart) { Process.Start(path); } } wixEvents.ShouldQuit(); }); wixEvents.ErrorObs.Subscribe(eventArgs => UserError.Throw("An installation error has occurred: " + eventArgs.ErrorMessage)); wixEvents.Engine.Detect(); }
public WixUiBootstrapper(IWiXEvents wixEvents, TinyIoCContainer testKernel = null, IRoutingState router = null) { Kernel = testKernel ?? createDefaultKernel(); Kernel.Register <IWixUiBootstrapper>(this); Kernel.Register <IScreen>(this); Kernel.Register(wixEvents); Router = router ?? new RoutingState(); WiXEvents = wixEvents; _BundledRelease = new Lazy <ReleaseEntry>(readBundledReleasesFile); registerExtensionDlls(Kernel); RxApp.ConfigureServiceLocator( (type, contract) => Kernel.Resolve(type, contract), (type, contract) => Kernel.ResolveAll(type), (c, t, s) => Kernel.Register(t, c, s)); UserError.RegisterHandler(ex => { if (wixEvents.Command.Display != Display.Full) { this.Log().Error(ex.ErrorMessage); wixEvents.ShouldQuit(); } var errorVm = RxApp.GetService <IErrorViewModel>(); errorVm.Error = ex; Router.Navigate.Execute(errorVm); return(Observable.Return(RecoveryOptionResult.CancelOperation)); }); var bundledPackageMetadata = openBundledPackage(); wixEvents.DetectPackageCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } // TODO: If the app is already installed, run it and bail if (wixEvents.Command.Action == LaunchAction.Uninstall) { var updateManager = new UpdateManager("http://lol", BundledRelease.PackageName, FrameworkVersion.Net40); var updateLock = updateManager.AcquireUpdateLock(); updateManager.FullUninstall() .ObserveOn(RxApp.DeferredScheduler) .Log(this, "Full uninstall") .Finally(updateLock.Dispose) .Subscribe( _ => wixEvents.Engine.Plan(LaunchAction.Uninstall), ex => UserError.Throw("Failed to uninstall application", ex), () => wixEvents.ShouldQuit()); return; } if (wixEvents.Command.Action == LaunchAction.Install) { if (wixEvents.Command.Display != Display.Full) { wixEvents.Engine.Plan(LaunchAction.Install); return; } var welcomeVm = RxApp.GetService <IWelcomeViewModel>(); welcomeVm.PackageMetadata = bundledPackageMetadata; welcomeVm.ShouldProceed.Subscribe(_ => wixEvents.Engine.Plan(LaunchAction.Install)); Router.Navigate.Execute(welcomeVm); } }); wixEvents.PlanCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Command.Action != LaunchAction.Install) { wixEvents.Engine.Apply(wixEvents.MainWindowHwnd); return; } // NB: Create a dummy subject to receive progress if we're in silent mode IObserver <int> progress = new Subject <int>(); if (wixEvents.Command.Display == Display.Full) { var installingVm = RxApp.GetService <IInstallingViewModel>(); progress = installingVm.ProgressValue; installingVm.PackageMetadata = bundledPackageMetadata; Router.Navigate.Execute(installingVm); } // NB: This bit of code is a bit clever. The binaries that WiX // has installed *itself* meets the qualifications for being a // Shimmer update directory (a RELEASES file and the corresponding // NuGet packages). // // So, in order to reuse some code and not write the same things // twice we're going to "Eigenupdate" from our own directory; // UpdateManager will operate in bootstrap mode and create a // local directory for us. // // Then, we create a *new* UpdateManager whose target is the normal // update URL - we can then apply delta updates against the bundled // NuGet package to get up to vCurrent. The reason we go through // this rigamarole is so that developers don't have to rebuild the // installer as often (never, technically). var fxVersion = determineFxVersionFromPackage(bundledPackageMetadata); var eigenUpdater = new UpdateManager(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), BundledRelease.PackageName, fxVersion); var eigenLock = eigenUpdater.AcquireUpdateLock(); var eigenUpdateProgress = eigenUpdater.CheckForUpdate() .SelectMany(x => eigenUpdater.DownloadReleases(x.ReleasesToApply)) .Finally(eigenLock.Dispose) .Select(x => x / 2) .Multicast(new Subject <int>()); eigenUpdateProgress.Subscribe(progress); eigenUpdateProgress.Connect(); var realUpdateProgress = eigenUpdateProgress.TakeLast(1) .SelectMany(_ => { var realUpdateManager = new UpdateManager(bundledPackageMetadata.ProjectUrl.ToString(), BundledRelease.PackageName, fxVersion); return(realUpdateManager.CheckForUpdate() .SelectMany(updateInfo => { return Observable.Concat( realUpdateManager.DownloadReleases(updateInfo.ReleasesToApply).Select(x => x * 0.75), realUpdateManager.ApplyReleases(updateInfo).Select(x => x * 0.25 + 75)) .Select(x => (int)x); }).LoggedCatch(this, Observable.Return(100), "Failed to update to latest remote version")); }) .Select(x => x / 2 + 50) .Multicast(new Subject <int>()); realUpdateProgress.Subscribe(progress); realUpdateProgress.Connect(); realUpdateProgress .TakeLast(1) .ObserveOn(RxApp.DeferredScheduler) .Subscribe( _ => wixEvents.Engine.Apply(wixEvents.MainWindowHwnd), ex => UserError.Throw("Failed to install application", ex)); }); wixEvents.ApplyCompleteObs.Subscribe(eventArgs => { var error = convertHResultToError(eventArgs.Status); if (error != null) { UserError.Throw(error); return; } if (wixEvents.Command.Display != Display.Full) { wixEvents.ShouldQuit(); } // TODO: Figure out what the "main app" is and run it }); wixEvents.ErrorObs.Subscribe(eventArgs => UserError.Throw("An installation error has occurred: " + eventArgs.ErrorMessage)); }