Beispiel #1
0
        protected virtual Task DbGc()
        {
            const string sql = "delete SheepJaxMessages where CreatedUtcTime < dateadd(minute, -10, GetUtcDate())";

            return(_connectionFactory().WithinTransaction(tx =>
                                                          TplHelper.Using(new SqlCommand(sql, tx.Connection, tx), cmd =>
                                                                          cmd.ExecuteNonQueryAsync().Success(_ => tx.Commit())
                                                                          )
                                                          ).Catch(_logger));
        }
Beispiel #2
0
 public SqlCommandBus(Func <SqlConnection> connectionFactory)
 {
     _connectionFactory = connectionFactory;
     _messageAdded      = new LazyPublisher <SqlCommandMessage>(observer =>
     {
         var isDisposed = false;
         _pollDbTask    = _pollDbTask.ContinueWith(t => TplHelper.DoWhile(() => PollDb(observer).ThenDelay(PollDbInterval), _ => !isDisposed)).Unwrap();
         _dbGcTask      = _dbGcTask.ContinueWith(t => TplHelper.DoWhile(() => DbGc().ThenDelay(DbGcInterval), _ => !isDisposed)).Unwrap();
         return(Disposable.Create(() => isDisposed = true));
     });
 }
Beispiel #3
0
 static void SetStatusText([NotNull] IMainWindowViewModel mainWindowViewModel, [NotNull] string statusText)
 {
     if (mainWindowViewModel == null)
     {
         throw new ArgumentNullException(nameof(mainWindowViewModel));
     }
     if (statusText == null)
     {
         throw new ArgumentNullException(nameof(statusText));
     }
     // Do not invoke logging inside this method because the logger is forwarded.
     // Circular invocation -> Stack overflow!
     TplHelper.RunSync(() => mainWindowViewModel.SetStatusTextAsync(statusText));
 }
Beispiel #4
0
        public virtual Task Consumed(CommandMessage last)
        {
            var msg = last as SqlCommandMessage;

            if (msg == null)
            {
                return(TplHelper.Empty);
            }

            const string sql    = "delete SheepJaxMessages where ClientId=@clientId and timestamp<@timestamp";
            var          dbTask = _connectionFactory().WithinTransaction(tx =>
                                                                         TplHelper.Using(new SqlCommand(sql, tx.Connection, tx)
            {
                Parameters =
                {
                    new SqlParameter("clientId",  msg.ClientId),
                    new SqlParameter("timestamp", msg.Timestamp)
                }
            }
                                                                                         , cmd => cmd.ExecuteNonQueryAsync().Finally(_ => tx.Commit())
                                                                                         )
                                                                         ).Catch(_logger);

            using (_cacheLock.BeginUpgradeableReadLock())
            {
                var node = _cache.Last;
                while (node != null && node.Value != last)
                {
                    node = node.Previous;
                }

                using (_cacheLock.BeginWriteLock())
                {
                    while (node != null)
                    {
                        var previousNode = node.Previous;
                        while (previousNode != null && previousNode.Value.ClientId != node.Value.ClientId)
                        {
                            previousNode = previousNode.Previous;
                        }

                        node.List.Remove(node);
                        node = previousNode;
                    }
                }
            }
            return(dbTask);
        }
Beispiel #5
0
        public static Task WithinTransaction(this SqlConnection conn, Func <SqlTransaction, Task> task)
        {
            SqlTransaction tx = null;

            try
            {
                conn.Open();
                tx = conn.BeginTransaction();
                return(task(tx).Finally(t => { tx.Dispose(); conn.Dispose(); }));
            }
            catch (Exception e)
            {
                if (tx != null)
                {
                    tx.Dispose();
                }
                conn.Dispose();
                return(TplHelper.FromException(e));
            }
        }
Beispiel #6
0
        private void SendMessage(Guid clientId, string msg)
        {
            const string sql = "insert into SheepJaxMessages (ClientId, Message) values (@clientId, @message)";

            Task.Factory.StartNew(delegate
            {
                _connectionFactory().WithinTransaction(tx =>
                                                       TplHelper.Using(new SqlCommand(sql, tx.Connection, tx)
                {
                    Parameters =
                    {
                        new SqlParameter("clientId", clientId),
                        new SqlParameter("message",  msg)
                    }
                },
                                                                       cmd => cmd.ExecuteNonQueryAsync().Finally(t => tx.Commit())
                                                                       )
                                                       );
            }).Catch(_logger);
        }
Beispiel #7
0
        protected virtual Task PollDb(IObserver <SqlCommandMessage> observer)
        {
            const string sql = "select ClientId, Message, CreatedUtcTime, Timestamp from SheepJaxMessages where CreatedUtcTime > dateadd(minute, -10, GetUtcDate())";

            return(_connectionFactory().WithinTransaction(tx =>
                                                          TplHelper.Using(new SqlCommand(sql, tx.Connection, tx), cmd =>
            {
                if (_lastTimestamp != null)
                {
                    cmd.CommandText += " and timestamp > @lastTimestamp";
                    cmd.Parameters.Add(new SqlParameter("lastTimestamp", _lastTimestamp));
                }
                cmd.CommandText += " order by timestamp asc";
                return cmd.ExecuteReaderAsync()
                .Select(reader =>
                {
                    using (reader)
                        while (reader.Read())
                        {
                            var timestamp = _lastTimestamp = new byte[8];
                            reader.GetBytes(3, 0, timestamp, 0, 8);
                            var msg = new SqlCommandMessage
                            {
                                ClientId = reader.GetGuid(0),
                                Message = reader.GetString(1),
                                CreatedUtcTime = reader.GetDateTime(2),
                                Timestamp = timestamp
                            };
                            using (_cacheLock.BeginWriteLock())
                            {
                                _cache.AddLast(msg);
                                observer.OnNext(msg);
                            }
                        }
                });
            })
                                                          ).Catch(_logger));
        }
Beispiel #8
0
 public DateTime?NowUtc(TimeSpan timeout = default)
 {
     return(TplHelper.RunSync(() => NowUtcAsync(timeout)));
 }
Beispiel #9
0
 public DateTime?NowUtc(string server, int port = 123, TimeSpan timeout = default)
 {
     return(TplHelper.RunSync(() => NowUtcAsync(server, port, timeout)));
 }
Beispiel #10
0
        public async Task TestInstallAsync()
        {
            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixture.BuildSnapApp();

            Assert.True(genesisSnapApp.Channels.Count >= 2);

            await using var testDirectory       = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem);
            using var genesisSnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext);
            var mainAssemblyDefinition = _baseFixture.BuildSnapExecutable(genesisSnapApp);

            genesisSnapReleaseBuilder
            .AddNuspecItem(mainAssemblyDefinition)
            .AddNuspecItem(mainAssemblyDefinition.BuildRuntimeConfigFilename(_snapFilesystem), mainAssemblyDefinition.BuildRuntimeConfig())
            .AddNuspecItem(_baseFixture.BuildLibrary("test1"))
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder);

            var loggerMock = new Mock <ILog>();

            var progressSource = new Mock <ISnapProgressSource>();

            progressSource.
            Setup(x => x.Raise(It.IsAny <int>()));

            var snapOsProcessManager = new Mock <ISnapOsProcessManager>();

            snapOsProcessManager
            .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) =>
            {
                var result = TplHelper.RunSync(() => _snapOsProcessManager.RunAsync(builder, cancellationToken));
                return(result);
            });
            snapOsProcessManager
            .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()))
            .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder));
            snapOsProcessManager
            .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken));
            _snapOsMock
            .Setup(x => x.Filesystem)
            .Returns(_snapFilesystem);
            _snapOsMock
            .Setup(x => x.ProcessManager)
            .Returns(snapOsProcessManager.Object);
            _snapOsMock
            .Setup(x => x.CreateShortcutsForExecutableAsync(
                       It.IsAny <SnapOsShortcutDescription>(),
                       It.IsAny <ILog>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.CompletedTask);

            await using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem);
            using var installCts          = new CancellationTokenSource();
            var snapCurrentChannel = genesisPackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow();

            await _snapInstaller.InstallAsync(
                genesisPackageContext.FullPackageAbsolutePath,
                baseDirectory.WorkingDirectory,
                genesisPackageContext.FullPackageSnapRelease,
                snapCurrentChannel,
                progressSource.Object,
                loggerMock.Object,
                cancellationToken : installCts.Token);

            var appDirectory          = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{genesisPackageContext.FullPackageSnapApp.Version}");
            var snapAppUpdated        = appDirectory.GetSnapAppFromDirectory(_snapFilesystem, _snapAppReader);
            var snapAppUpdatedChannel = snapAppUpdated.GetCurrentChannelOrThrow();

            Assert.Equal(snapCurrentChannel.Name, snapAppUpdatedChannel.Name);

            var coreRunExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory,
                                                         _snapEmbeddedResources.GetCoreRunExeFilenameForSnapApp(genesisPackageContext.FullPackageSnapApp));
            var appExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory,
                                                     $"app-{genesisSnapReleaseBuilder.SnapApp.Version}", genesisSnapReleaseBuilder.CoreRunExe);
            var snapInstalledArguments = $"--snapx-installed {genesisPackageContext.FullPackageSnapApp.Version.ToNormalizedString()}";
            var snapFirstRunArguments  = $"--snapx-first-run {genesisPackageContext.FullPackageSnapApp.Version.ToNormalizedString()}";

            progressSource.Verify(x => x.Raise(It.Is <int>(v => v == 100)), Times.Once);

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
                snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                It.Is <string>(v => v == coreRunExe), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);
                snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                It.Is <string>(v => v == appExe), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);
            }

            _snapOsMock.Verify(x => x.KillAllProcessesInsideDirectory(
                                   It.Is <string>(v => v == baseDirectory.WorkingDirectory)), Times.Once);

            _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                   It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(),
                                   It.IsAny <CancellationToken>()), Times.Once);

            _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                   It.Is <SnapOsShortcutDescription>(v => v.ExeAbsolutePath == coreRunExe),
                                   It.Is <ILog>(v => v != null), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);

            snapOsProcessManager.Verify(x => x.RunAsync(
                                            It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()), Times.Once);

            snapOsProcessManager.Verify(x => x.RunAsync(
                                            It.Is <ProcessStartInfoBuilder>(v => v.Filename == appExe &&
                                                                            v.Arguments == snapInstalledArguments),
                                            It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);

            snapOsProcessManager.Verify(x => x.StartNonBlocking(
                                            It.Is <ProcessStartInfoBuilder>(v => v.Filename == appExe
                                                                            & v.Arguments == snapFirstRunArguments)), Times.Once);
            snapOsProcessManager.Verify(x => x.StartNonBlocking(
                                            It.IsAny <ProcessStartInfoBuilder>()), Times.Once);
        }
Beispiel #11
0
        public async Task TestUpdateAsync()
        {
            var snapAppsReleases = new SnapAppsReleases();

            var genesisSnapApp = _baseFixture.BuildSnapApp();
            var update1SnapApp = _baseFixture.Bump(genesisSnapApp);
            var update2SnapApp = _baseFixture.Bump(update1SnapApp);

            await using var testDirectory       = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem);
            using var genesisSnapReleaseBuilder =
                      _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext);
            using var update1SnapReleaseBuilder =
                      _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, update1SnapApp, _snapReleaseBuilderContext);
            using var update2SnapReleaseBuilder =
                      _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, update2SnapApp, _snapReleaseBuilderContext);
            var mainExecutable = _baseFixture.BuildSnapExecutable(genesisSnapApp);

            genesisSnapReleaseBuilder
            .AddNuspecItem(mainExecutable)
            .AddNuspecItem(mainExecutable.BuildRuntimeConfigFilename(_snapFilesystem), mainExecutable.BuildRuntimeConfig())
            .AddNuspecItem(_baseFixture.BuildLibrary("test1"))
            .AddSnapDll();

            update1SnapReleaseBuilder
            .AddNuspecItem(genesisSnapReleaseBuilder, 0)
            .AddNuspecItem(genesisSnapReleaseBuilder, 1)
            .AddNuspecItem(genesisSnapReleaseBuilder, 2)
            .AddNuspecItem(_baseFixture.BuildLibrary("test2"))
            .AddSnapDll();

            update2SnapReleaseBuilder
            .AddNuspecItem(update1SnapReleaseBuilder, 0)
            .AddNuspecItem(update1SnapReleaseBuilder, 1)
            .AddNuspecItem(update1SnapReleaseBuilder, 2)
            .AddNuspecItem(update1SnapReleaseBuilder, 3)
            .AddNuspecItem(_baseFixture.BuildLibrary("test3"))
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder);

            using (await _baseFixture.BuildPackageAsync(update1SnapReleaseBuilder))
            {
                using var update2PackageContext = await _baseFixture.BuildPackageAsync(update2SnapReleaseBuilder);

                var loggerMock = new Mock <ILog>();

                var progressSource = new Mock <ISnapProgressSource>();
                progressSource.
                Setup(x => x.Raise(It.IsAny <int>()));

                var snapOsProcessManager = new Mock <ISnapOsProcessManager>();
                snapOsProcessManager
                .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()))
                .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) =>
                {
                    var result = TplHelper.RunSync(() => _snapOsProcessManager.RunAsync(builder, cancellationToken));
                    return(result);
                });
                snapOsProcessManager
                .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()))
                .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder));
                snapOsProcessManager
                .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
                .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken));
                _snapOsMock
                .Setup(x => x.Filesystem)
                .Returns(_snapFilesystem);
                _snapOsMock
                .Setup(x => x.ProcessManager)
                .Returns(snapOsProcessManager.Object);
                _snapOsMock
                .Setup(x => x.CreateShortcutsForExecutableAsync(
                           It.IsAny <SnapOsShortcutDescription>(),
                           It.IsAny <ILog>(),
                           It.IsAny <CancellationToken>()))
                .Returns(Task.CompletedTask);

                await using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem);
                using var updateCts           = new CancellationTokenSource();
                await _snapInstaller.InstallAsync(
                    genesisPackageContext.FullPackageAbsolutePath,
                    baseDirectory.WorkingDirectory,
                    genesisPackageContext.FullPackageSnapRelease,
                    genesisPackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow(),
                    cancellationToken : updateCts.Token);

                _snapOsMock.Invocations.Clear();
                snapOsProcessManager.Invocations.Clear();

                var update2FullNupkgAbsolutePath = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, "packages",
                                                                               update2PackageContext.FullPackageSnapRelease.BuildNugetFilename());

                await _snapFilesystem.FileCopyAsync(update2PackageContext.FullPackageAbsolutePath,
                                                    update2FullNupkgAbsolutePath, default);

                await _snapInstaller.UpdateAsync(
                    baseDirectory.WorkingDirectory,
                    update2PackageContext.FullPackageSnapRelease,
                    update2PackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow(),
                    progressSource.Object,
                    loggerMock.Object,
                    updateCts.Token);

                var coreRunExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, update2SnapReleaseBuilder.CoreRunExe);
                var appExe     = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory,
                                                             $"app-{update2SnapReleaseBuilder.SnapApp.Version}", update2SnapReleaseBuilder.CoreRunExe);
                var snapUpdatedArguments = $"--snapx-updated {update2SnapReleaseBuilder.SnapApp.Version.ToNormalizedString()}";

                progressSource.Verify(x => x.Raise(It.Is <int>(v => v == 100)), Times.Once);

                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                    It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
                    snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                    It.Is <string>(v => v == coreRunExe), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);
                    snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                    It.Is <string>(v => v == appExe), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);
                }

                _snapOsMock.Verify(x => x.KillAllProcessesInsideDirectory(
                                       It.IsAny <string>()), Times.Never);

                _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                       It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(),
                                       It.IsAny <CancellationToken>()), Times.Once);

                _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                       It.Is <SnapOsShortcutDescription>(v => v.ExeAbsolutePath == coreRunExe),
                                       It.Is <ILog>(v => v != null), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);

                snapOsProcessManager.Verify(x => x.RunAsync(It.Is <ProcessStartInfoBuilder>(
                                                                v => v.Filename == appExe && v.Arguments == snapUpdatedArguments),
                                                            It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);

                snapOsProcessManager.Verify(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()), Times.Never);
            }
        }
Beispiel #12
0
        public async Task TestInstallAsync_Different_Channel()
        {
            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixture.BuildSnapApp();

            Assert.True(genesisSnapApp.Channels.Count >= 2);

            await using var testDirectory       = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem);
            using var genesisSnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext);
            var mainAssemblyDefinition = _baseFixture.BuildSnapExecutable(genesisSnapApp);

            genesisSnapReleaseBuilder
            .AddNuspecItem(mainAssemblyDefinition)
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder);

            var loggerMock = new Mock <ILog>();

            var snapOsProcessManager = new Mock <ISnapOsProcessManager>();

            snapOsProcessManager
            .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) =>
            {
                var result = TplHelper.RunSync(() => _snapOsProcessManager.RunAsync(builder, cancellationToken));
                return(result);
            });
            snapOsProcessManager
            .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()))
            .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder));
            snapOsProcessManager
            .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken));
            _snapOsMock
            .Setup(x => x.Filesystem)
            .Returns(_snapFilesystem);
            _snapOsMock
            .Setup(x => x.ProcessManager)
            .Returns(snapOsProcessManager.Object);
            _snapOsMock
            .Setup(x => x.CreateShortcutsForExecutableAsync(
                       It.IsAny <SnapOsShortcutDescription>(),
                       It.IsAny <ILog>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.CompletedTask);

            await using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem);
            using var installCts          = new CancellationTokenSource();
            var nextSnapChannel = genesisSnapApp.GetNextChannel();

            await _snapInstaller.InstallAsync(
                genesisPackageContext.FullPackageAbsolutePath,
                baseDirectory.WorkingDirectory,
                genesisPackageContext.FullPackageSnapRelease,
                nextSnapChannel,
                null,
                loggerMock.Object,
                cancellationToken : installCts.Token);

            var appDirectory          = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{genesisPackageContext.FullPackageSnapApp.Version}");
            var snapAppUpdated        = appDirectory.GetSnapAppFromDirectory(_snapFilesystem, _snapAppReader);
            var snapAppUpdatedChannel = snapAppUpdated.GetCurrentChannelOrThrow();

            Assert.Equal(nextSnapChannel.Name, snapAppUpdatedChannel.Name);
        }
Beispiel #13
0
        static async Task <(int exitCode, SnapInstallerType installerType)> MainImplAsync([NotNull] ISnapInstallerEnvironment snapInstallerEnvironment,
                                                                                          [NotNull] ILog snapInstallerLogger, bool headless)
        {
            if (snapInstallerEnvironment == null)
            {
                throw new ArgumentNullException(nameof(snapInstallerEnvironment));
            }
            if (snapInstallerLogger == null)
            {
                throw new ArgumentNullException(nameof(snapInstallerLogger));
            }

            var snapOs = snapInstallerEnvironment.Container.GetInstance <ISnapOs>();
            var snapEmbeddedResources = snapInstallerEnvironment.Container.GetInstance <ISnapEmbeddedResources>();
            var snapCryptoProvider    = snapInstallerEnvironment.Container.GetInstance <ISnapCryptoProvider>();

            var thisExeWorkingDirectory = snapInstallerEnvironment.Io.ThisExeWorkingDirectory;
            var workingDirectory        = snapInstallerEnvironment.Io.WorkingDirectory;

            TplHelper.RunSync(() => snapEmbeddedResources.ExtractCoreRunLibAsync(snapOs.Filesystem, snapCryptoProvider, thisExeWorkingDirectory, snapOs.OsPlatform));
            var coreRunLib    = new CoreRunLib(snapOs.Filesystem, snapOs.OsPlatform, thisExeWorkingDirectory);
            var snapInstaller = snapInstallerEnvironment.Container.GetInstance <ISnapInstaller>();
            var snapInstallerEmbeddedResources = snapInstallerEnvironment.Container.GetInstance <ISnapInstallerEmbeddedResources>();
            var snapPack       = snapInstallerEnvironment.Container.GetInstance <ISnapPack>();
            var snapAppReader  = snapInstallerEnvironment.Container.GetInstance <ISnapAppReader>();
            var snapAppWriter  = snapInstallerEnvironment.Container.GetInstance <ISnapAppWriter>();
            var snapFilesystem = snapInstallerEnvironment.Container.GetInstance <ISnapFilesystem>();

            snapFilesystem.DirectoryCreateIfNotExists(snapOs.SpecialFolders.InstallerCacheDirectory);
            var snapPackageManager         = snapInstallerEnvironment.Container.GetInstance <ISnapPackageManager>();
            var snapExtractor              = snapInstallerEnvironment.Container.GetInstance <ISnapExtractor>();
            var nugetServiceCommandInstall = new NugetService(snapOs.Filesystem, new NugetLogger(snapInstallerLogger));

            Task <(int exitCode, SnapInstallerType installerType)> RunInstallerAsync()
            {
                return(InstallAsync(snapInstallerEnvironment, snapInstallerEmbeddedResources,
                                    snapInstaller, snapFilesystem, snapPack, snapOs, coreRunLib, snapAppReader,
                                    snapAppWriter, nugetServiceCommandInstall, snapPackageManager, snapExtractor, snapInstallerLogger,
                                    headless));
            }

            try
            {
                var mutexName = snapCryptoProvider.Sha256(Encoding.UTF8.GetBytes(workingDirectory));
                _mutexSingleInstanceWorkingDirectory = new Mutex(true, $"Global\\{mutexName}", out var createdNew);
                if (!createdNew)
                {
                    snapInstallerLogger.Error("Setup is already running, exiting...");
                    return(1, SnapInstallerType.None);
                }

                _mutexIsTaken = true;
            }
            catch (Exception e)
            {
                snapInstallerLogger.ErrorException("Error creating installer mutex, exiting...", e);
                return(1, SnapInstallerType.None);
            }

            return(await RunInstallerAsync());
        }