예제 #1
0
        public void EigenUpdateWithoutUpdateURL()
        {
            string dir;
            string outDir;

            using (Utility.WithTempDirectory(out outDir))
            using (IntegrationTestHelper.WithFakeInstallDirectory(out dir)) {
                var di = new DirectoryInfo(dir);
                var progress = new Subject<int>();

                var bundledRelease = ReleaseEntry.GenerateFromFile(di.GetFiles("*.nupkg").First().FullName);
                var fixture = new InstallManager(bundledRelease, outDir);
                var pkg = new ZipPackage(Path.Combine(dir, "SampleUpdatingApp.1.1.0.0.nupkg"));

                var progressValues = new List<int>();
                progress.Subscribe(progressValues.Add);

                fixture.ExecuteInstall(dir, pkg, progress).Wait();

                var filesToLookFor = new[] {
                    "SampleUpdatingApp\\app-1.1.0.0\\SampleUpdatingApp.exe",
                    "SampleUpdatingApp\\packages\\RELEASES",
                    "SampleUpdatingApp\\packages\\SampleUpdatingApp.1.1.0.0.nupkg",
                };

                filesToLookFor.ForEach(f => Assert.True(File.Exists(Path.Combine(outDir, f)), "Could not find file: " + f));

                // Progress should be monotonically increasing
                progressValues.Count.ShouldBeGreaterThan(2);
                progressValues.Zip(progressValues.Skip(1), (prev, cur) => cur - prev).All(x => x > 0).ShouldBeTrue();
            }
        }
예제 #2
0
        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();
        }
예제 #3
0
        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;
                }

                if (wixEvents.Action == LaunchAction.Uninstall) {

                    if (wixEvents.DisplayMode != Display.Full) {
                        this.Log().Info("Shimmer is doing a silent uninstall! Sneaky!");
                        wixEvents.Engine.Plan(LaunchAction.Uninstall);
                        return;
                    }

                    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 => {
                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();
        }
예제 #4
0
        public void InstallWithContentInPackageDropsInSameFolder()
        {
            string dir;
            string outDir;

            var package = "ProjectWithContent.1.0.0.0-beta-full.nupkg";

            using (Utility.WithTempDirectory(out outDir))
            using (IntegrationTestHelper.WithFakeInstallDirectory(package, out dir))
            {
                try
                {
                    var di = new DirectoryInfo(dir);

                    var bundledRelease = ReleaseEntry.GenerateFromFile(di.GetFiles("*.nupkg").First().FullName);
                    var fixture = new InstallManager(bundledRelease, outDir);
                    var pkg = new ZipPackage(Path.Combine(dir, package));

                    fixture.ExecuteInstall(dir, pkg).Wait();

                    var filesToLookFor = new[] {
                        "ProjectWithContent\\app-1.0.0.0\\project-with-content.exe",
                        "ProjectWithContent\\app-1.0.0.0\\some-words.txt",
                        "ProjectWithContent\\app-1.0.0.0\\dir\\item-in-subdirectory.txt",
                        "ProjectWithContent\\packages\\RELEASES",
                        "ProjectWithContent\\packages\\ProjectWithContent.1.0.0.0-beta-full.nupkg",
                    };

                    filesToLookFor.ForEach(f => Assert.True(File.Exists(Path.Combine(outDir, f)), "Could not find file: " + f));
                }
                finally
                {
                    Directory.Delete(dir, true);
                }
            }
        }
예제 #5
0
        public void UninstallRemovesEverything()
        {
            string dir;
            string appDir;

            using (IntegrationTestHelper.WithFakeInstallDirectory(out dir))
            using (IntegrationTestHelper.WithFakeAlreadyInstalledApp(out appDir)) {
                var di = new DirectoryInfo(dir);
                var progress = new Subject<int>();

                var bundledRelease = ReleaseEntry.GenerateFromFile(di.GetFiles("*.nupkg").First().FullName);
                var fixture = new InstallManager(bundledRelease, appDir);

                var progressValues = new List<int>();
                progress.Subscribe(progressValues.Add);

                fixture.ExecuteUninstall().First();

                di = new DirectoryInfo(appDir);
                di.GetDirectories().Any().ShouldBeFalse();
                di.GetFiles().Any().ShouldBeFalse();
            }
        }
예제 #6
0
        public void UninstallDoesntCrashOnMissingAppDirectory()
        {
            string dir;
            string appDir;
            InstallManager fixture;

            using (IntegrationTestHelper.WithFakeInstallDirectory(out dir))
            using (IntegrationTestHelper.WithFakeAlreadyInstalledApp(out appDir)) {
                var di = new DirectoryInfo(dir);

                var bundledRelease = ReleaseEntry.GenerateFromFile(di.GetFiles("*.nupkg").First().FullName);
                fixture = new InstallManager(bundledRelease, appDir);
            }

            fixture.ExecuteUninstall().First();
        }