/// <inheritdoc />
        protected override async Task ExecuteAsync(ApplicationViewModel?viewModel, object?parameter)
        {
            if (!(viewModel?.Parent is MainWindowDialogModel mainWindowDialogModel))
            {
                return;
            }

            var dialogModel  = _viewModelService.CreateViewModel <InstallerBundleDialogModel>(viewModel.SelectedInstallerBundle);
            var dialogResult = _dialogService.ShowDialog(dialogModel);

            if (dialogResult != true)
            {
                return;
            }

            var installers = viewModel.SelectedInstallerBundle?.Installers.Where(i => i.SelectedOperation != InstallerOperation.DoNothing).ToList();

            if (installers == null || !installers.Any())
            {
                return;
            }

            mainWindowDialogModel.CurrentInstallation      = _viewModelService.CreateViewModel <InstallationViewModel>(mainWindowDialogModel);
            mainWindowDialogModel.CurrentInstallation.Name = viewModel.Name;
            mainWindowDialogModel.CurrentInstallation.TotalInstallerFileCount = installers.Count;

            try
            {
                mainWindowDialogModel.RecentInstallationResult = await ViewModelInstallService.Custom(
                    _viewModelService,
                    _installService,
                    _notificationService,
                    _uriService,
                    mainWindowDialogModel.CurrentInstallation,
                    installers,
                    viewModel.EnableSilentInstallation,
                    viewModel.DisableReboot,
                    viewModel.EnableInstallationLogging,
                    viewModel.AutomaticallyDeleteInstallationLogs,
                    viewModel.KeepNewestInstallationLogs,
                    false,
                    _downloadFolderPath);
            }
            finally
            {
                mainWindowDialogModel.CurrentInstallation.Dispose();
                mainWindowDialogModel.CurrentInstallation = null;
            }

            mainWindowDialogModel.RefreshApplicationsCommand?.Execute(null);

            if (mainWindowDialogModel.RecentInstallationResult.InstallationResults.Any(r => r.State != InstallationResultState.Success && r.State != InstallationResultState.Skipped))
            {
                _dialogService.ShowDialog(mainWindowDialogModel.RecentInstallationResult);
            }
            else
            {
                _notificationService.ShowSuccess(Strings.OperationSuccessfull, () => _dialogService.ShowDialog(mainWindowDialogModel.RecentInstallationResult));
            }
        }
示例#2
0
        private static InstallationResultViewModel CreateInstallationFailedResult(IViewModelService viewModelService, InstallerViewModel installerViewModel,
                                                                                  Exception exception)
        {
            var installationResultViewModel = viewModelService.CreateViewModel <InstallationResultViewModel>(installerViewModel);

            installationResultViewModel.State     = InstallationResultState.InstallationFailed;
            installationResultViewModel.Exception = viewModelService.CreateViewModel <ExceptionViewModel>(installationResultViewModel, exception);
            return(installationResultViewModel);
        }
示例#3
0
        private async Task CheckForUpdate(IUpdateService updateService, INotificationService notificationService, MainWindowDialogModel mainDialogModel)
        {
            var updateResult = await updateService.IsUpdateAvailable();

            if (!updateResult.IsUpdateAvailable)
            {
                mainDialogModel.AvailableUpdate = null;
                return;
            }

            mainDialogModel.AvailableUpdate = _viewModelService.CreateViewModel <UpdateDialogModel>(mainDialogModel, updateResult);
            notificationService.ShowInfo(Strings.UpdateAvailableDescription, () =>
            {
                mainDialogModel.ShowUpdateDialogCommand.Execute(null);
            });
        }
示例#4
0
        private static InstallationResultViewModel CreateSkippedResult(IViewModelService viewModelService, InstallerViewModel installerViewModel)
        {
            var installationResultViewModel = viewModelService.CreateViewModel <InstallationResultViewModel>(installerViewModel);

            installationResultViewModel.State = InstallationResultState.Skipped;
            return(installationResultViewModel);
        }
示例#5
0
        /// <inheritdoc />
        protected override async Task ExecuteAsync(MainWindowDialogModel?viewModel, object?parameter)
        {
            if (viewModel == null)
            {
                return;
            }

            var dialogModel = _viewModelService.CreateViewModel <ApplicationDialogModel>(viewModel);

            do
            {
                if (_dialogService.ShowDialog(dialogModel) != true)
                {
                    return;
                }

                if (!dialogModel.IsValid)
                {
                    _dialogService.ShowErrorDialog(Strings.DialogInputNotValid, Strings.Error);
                }
            } while (!dialogModel.IsValid);

            await _viewModelService.SaveViewModelAsync(dialogModel);

            await _viewModelService.UpdateViewModelAsync(viewModel);
        }
示例#6
0
        /// <inheritdoc />
        protected override void Execute(MainWindowDialogModel?viewModel, object?parameter)
        {
            if (viewModel == null)
            {
                return;
            }

            var dialogModel = _viewModelService.CreateViewModel <AboutDialogModel>(viewModel);

            _dialogService.ShowDialog(dialogModel);
        }
示例#7
0
        /// <inheritdoc />
        protected override async Task ExecuteAsync(ApplicationViewModel?viewModel, object?parameter)
        {
            if (viewModel == null)
            {
                return;
            }

            var dialogModel = _viewModelService.CreateViewModel <ApplicationDialogModel>(viewModel);

            if (_dialogService.ShowDialog(dialogModel) != true)
            {
                return;
            }

            await _viewModelService.SaveViewModelAsync(dialogModel);

            await _viewModelService.UpdateViewModelAsync(viewModel);
        }
示例#8
0
        protected override async void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            // Ensure the current culture passed into bindings is the OS culture.
            // By default, WPF uses en-US as the culture, regardless of the system settings.
            // https://stackoverflow.com/a/520334
            FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

            var kernel = new StandardKernel(new AppModule());

            _dialogService    = kernel.Get <IDialogService>();
            _viewModelService = kernel.Get <IViewModelService>(new ConstructorArgument("tmpFolderPath", AppTmpFolderPath));

            var configurationService = kernel.Get <IConfigurationService>();
            var isFirstLaunch        = false;

            try
            {
                await configurationService.LoadConfigurationAsync();
            }
            catch (Exception exception)
            {
                Log.Error("Loading configuration failed, will create a new one", exception);
                configurationService.Configuration.SelectedTheme = GetSystemColorScheme();
                isFirstLaunch = true;
            }

            kernel.Get <IThemeService>().SetTheme(configurationService.Configuration.SelectedTheme);

            var mainDialogModel = _viewModelService.CreateViewModel <MainWindowDialogModel>();

            _dialogService.Show(mainDialogModel);

            mainDialogModel.RefreshApplicationsCommand.Execute(null);

            var          assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
            const string repository      = "nkristek/Stein";
            var          updateService   = kernel.Get <IUpdateService>(
                new ConstructorArgument("currentVersion", assemblyVersion),
                new ConstructorArgument("repository", repository));
            var notificationService = kernel.Get <INotificationService>();

            MainWindow.Closing += (sender, args) => notificationService.Dispose();
            var updateTask = CheckForUpdate(updateService, notificationService, mainDialogModel);

            if (isFirstLaunch)
            {
                var welcomeDialog = _viewModelService.CreateViewModel <WelcomeDialogModel>(mainDialogModel);
                _dialogService.ShowDialog(welcomeDialog);
            }

            try
            {
                await updateTask;
            }
            catch (Exception exception)
            {
                Log.Error("Checking for update failed.", exception);
            }
        }
示例#9
0
        private static async Task <InstallationResultViewModel> PerformOperation(IViewModelService viewModelService, IInstallService installService, INotificationService notificationService, InstallerViewModel installerViewModel, InstallationViewModel currentInstallationViewModel, string installerFilePath, bool enableSilentInstallation, bool disableReboot,
                                                                                 bool enableInstallationLogging, string?logFolderPath = null)
        {
            string?installLogFilePath   = null;
            string?uninstallLogFilePath = null;

            if (enableInstallationLogging)
            {
                if (String.IsNullOrEmpty(logFolderPath))
                {
                    Log.Warn("Installation logging is enabled but the logFolderPath is null or empty.");
                }
                else if (!Directory.Exists(logFolderPath))
                {
                    Log.Warn("logFolderPath is set but the directory doesn't exist.");
                }
                else
                {
                    installLogFilePath   = GetLogFilePathForInstaller(logFolderPath !, installerViewModel.Name ?? "unkown", "install");
                    uninstallLogFilePath = GetLogFilePathForInstaller(logFolderPath !, installerViewModel.Name ?? "unkown", "uninstall");
                }
            }

            var installArguments = GetArguments(
                enableSilentInstallation,
                disableReboot,
                enableInstallationLogging,
                installLogFilePath).ToArray();
            var uninstallArguments = GetArguments(
                enableSilentInstallation,
                disableReboot,
                enableInstallationLogging,
                uninstallLogFilePath).ToArray();

            var installationResultViewModel = viewModelService.CreateViewModel <InstallationResultViewModel>(installerViewModel);

            try
            {
                switch (installerViewModel.SelectedOperation)
                {
                case InstallerOperation.Install:
                    if (installerViewModel.IsInstalled != false)
                    {
                        if (installerViewModel.IsInstalled == null)
                        {
                            Log.Warn($"Installation status of file \"{installerViewModel.FileName}\" is unavailable, trying to uninstall.");
                        }
                        else
                        {
                            Log.Info($"The application \"{installerViewModel.Name}\" with ProductCode \"{installerViewModel.ProductCode}\" is already installed. It will now be uninstalled first.");
                        }

                        if (String.IsNullOrWhiteSpace(installerViewModel.ProductCode))
                        {
                            var exception = new Exception($"Uninstalling \"{installerViewModel.FileName}\" failed: ProductCode is not set.");
                            Log.Error(exception);
                            if (installerViewModel.IsInstalled == true)
                            {
                                return(CreateInstallationFailedResult(viewModelService, installerViewModel, exception));
                            }
                        }
                        else
                        {
                            Log.Info($"Uninstalling application of installer \"{installerViewModel.FileName}\" now.");
                            currentInstallationViewModel.CurrentOperation = InstallationOperation.Uninstall;

                            if (enableInstallationLogging && uninstallLogFilePath is string)
                            {
                                installationResultViewModel.InstallationLogFilePaths.Add(uninstallLogFilePath);
                            }

                            try
                            {
                                await installService.PerformAsync(new Operation(installerViewModel.ProductCode, OperationType.Uninstall, uninstallArguments));

                                Log.Info($"Finished uninstalling.");
                            }
                            catch (Exception exception)
                            {
                                // suppress exception if installation status is unknown
                                if (installerViewModel.IsInstalled == true)
                                {
                                    throw;
                                }

                                Log.Warn("Uninstalling failed, but since the installation state is unavailable, the operation will continue", exception);
                            }
                        }
                    }

                    Log.Info($"Installing \"{installerViewModel.FileName}\" now.");
                    currentInstallationViewModel.CurrentOperation = InstallationOperation.Install;
                    if (enableInstallationLogging && installLogFilePath is string)
                    {
                        installationResultViewModel.InstallationLogFilePaths.Add(installLogFilePath);
                    }
                    await installService.PerformAsync(new Operation(installerFilePath, OperationType.Install, installArguments));

                    Log.Info($"Finished installing.");
                    installationResultViewModel.State = InstallationResultState.Success;
                    break;

                case InstallerOperation.Uninstall:
                    if (installerViewModel.IsInstalled == null)
                    {
                        Log.Warn($"Installation status of file \"{installerViewModel.FileName}\" is unavailable, trying to uninstall.");
                    }
                    else if (installerViewModel.IsInstalled == false)
                    {
                        Log.Warn($"The application \"{installerViewModel.Name}\" with ProductCode \"{installerViewModel.ProductCode}\" is not installed. Trying to uninstall anyways but it will likely fail.");
                    }
                    else
                    {
                        Log.Info($"The application \"{installerViewModel.Name}\" with ProductCode \"{installerViewModel.ProductCode}\" will now be uninstalled.");
                    }

                    if (String.IsNullOrWhiteSpace(installerViewModel.ProductCode))
                    {
                        var exception = new Exception($"Uninstalling \"{installerViewModel.FileName}\" failed: ProductCode is not set.");
                        Log.Error(exception);
                        return(CreateInstallationFailedResult(viewModelService, installerViewModel, exception));
                    }

                    Log.Info($"Uninstalling application of installer \"{installerViewModel.FileName}\" now.");
                    currentInstallationViewModel.CurrentOperation = InstallationOperation.Uninstall;
                    if (enableInstallationLogging && uninstallLogFilePath is string)
                    {
                        installationResultViewModel.InstallationLogFilePaths.Add(uninstallLogFilePath);
                    }
                    await installService.PerformAsync(new Operation(installerViewModel.ProductCode, OperationType.Uninstall, uninstallArguments));

                    Log.Info($"Finished uninstalling.");
                    installationResultViewModel.State = InstallationResultState.Success;
                    break;

                default:
                    installationResultViewModel.State = InstallationResultState.Skipped;
                    break;
                }
            }
#pragma warning disable CA1031 // Do not catch general exception types
            catch (Exception exception)
            {
                Log.Error(exception);
                var errorMessage = installerViewModel.SelectedOperation switch
                {
                    InstallerOperation.Install => Strings.InstallationOfXFailed,
                    InstallerOperation.Uninstall => Strings.UninstallationOfXFailed,
                    _ => Strings.OperationOfXFailed,
                };
                notificationService.ShowError(String.Format(errorMessage, installerViewModel.Name));
                return(CreateInstallationFailedResult(viewModelService, installerViewModel, exception));
            }
#pragma warning restore CA1031 // Do not catch general exception types

            return(installationResultViewModel);
        }
示例#10
0
        public static async Task <InstallationResultDialogModel> Custom(IViewModelService viewModelService, IInstallService installService, INotificationService notificationService, IUriService uriService, InstallationViewModel currentInstallationViewModel, IReadOnlyList <InstallerViewModel> installerViewModels, bool enableSilentInstallation, bool disableReboot,
                                                                        bool enableInstallationLogging, bool automaticallyDeleteInstallationLogs, int keepNewestInstallationLogs, bool filterDuplicateInstallers, string downloadFolderPath)
        {
            if (viewModelService == null)
            {
                throw new ArgumentNullException(nameof(viewModelService));
            }
            if (installService == null)
            {
                throw new ArgumentNullException(nameof(installService));
            }
            if (notificationService == null)
            {
                throw new ArgumentNullException(nameof(notificationService));
            }
            if (uriService == null)
            {
                throw new ArgumentNullException(nameof(uriService));
            }
            if (currentInstallationViewModel == null)
            {
                throw new ArgumentNullException(nameof(currentInstallationViewModel));
            }
            if (installerViewModels == null)
            {
                throw new ArgumentNullException(nameof(installerViewModels));
            }
            if (String.IsNullOrEmpty(downloadFolderPath))
            {
                throw new ArgumentNullException(nameof(downloadFolderPath));
            }

            var cancellationToken             = currentInstallationViewModel.CancellationTokenSource.Token;
            var installationResultDialogModel = viewModelService.CreateViewModel <InstallationResultDialogModel>(currentInstallationViewModel);

            var logFolderPath = enableInstallationLogging && currentInstallationViewModel.Name is string installationName?GetOrCreateLogFileFolderPath(installationName) : null;

            installationResultDialogModel.LogFolderPath = logFolderPath;

            var sessionDownloadPath = Path.Combine(downloadFolderPath, currentInstallationViewModel.Name);

            if (!Directory.Exists(sessionDownloadPath))
            {
                Directory.CreateDirectory(sessionDownloadPath);
            }
            using var tempFileCollection = new TempFileCollection(sessionDownloadPath);

            Log.Info($"Starting download of {installerViewModels.Count} files.");
            var downloadResults = await Download(notificationService, installerViewModels, currentInstallationViewModel, tempFileCollection, 3, cancellationToken);

            Log.Info($"Download finished.");

            if (downloadResults.Any(dr => dr.Value.Result == DownloadResultState.Cancelled))
            {
                Log.Info("At least one download was cancelled, installation will be skipped.");

                foreach (var download in downloadResults)
                {
                    currentInstallationViewModel.CurrentInstallerIndex++;
                    var installerViewModel = download.Key;
                    var downloadResult     = download.Value;

                    var installationResultViewModel = downloadResult.Result switch
                    {
                        DownloadResultState.Failed => CreateDownloadFailedResult(viewModelService, installerViewModel, downloadResult),
                        _ => CreateCancelledResult(viewModelService, installerViewModel)
                    };

                    installationResultDialogModel.InstallationResults.Add(installationResultViewModel);
                    currentInstallationViewModel.ProcessedInstallerFileCount++;
                }

                return(installationResultDialogModel);
            }

            currentInstallationViewModel.TotalInstallerFileCount = downloadResults.Count;
            var installedInstallerViewModels = new List <InstallerViewModel>();

            foreach (var download in downloadResults)
            {
                currentInstallationViewModel.CurrentInstallerIndex++;
                var installerViewModel = download.Key;
                var downloadResult     = download.Value;

                if (downloadResult.Result == DownloadResultState.Failed)
                {
                    var failedResultViewModel = CreateDownloadFailedResult(viewModelService, installerViewModel, downloadResult);
                    installationResultDialogModel.InstallationResults.Add(failedResultViewModel);
                    currentInstallationViewModel.ProcessedInstallerFileCount++;
                    continue;
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    var cancelledResultViewModel = CreateCancelledResult(viewModelService, installerViewModel);
                    installationResultDialogModel.InstallationResults.Add(cancelledResultViewModel);
                    currentInstallationViewModel.ProcessedInstallerFileCount++;
                    continue;
                }

                if (downloadResult.Result != DownloadResultState.CompletedSuccessfully || !(downloadResult is SucceededDownloadResult succeededDownloadResult))
                {
                    Exception exception;
                    if (downloadResult.Result != DownloadResultState.CompletedSuccessfully)
                    {
                        exception = new Exception($"Unexpected download result (got \"{downloadResult.Result.ToString()}\", should be \"{nameof(DownloadResultState.CompletedSuccessfully)}\")");
                    }
                    else
                    {
                        exception = new Exception($"Unexpected download result type (got \"{downloadResult.GetType().Name}\", should be \"{nameof(SucceededDownloadResult)}\")");
                    }
                    Log.Error(exception);
                    var failedResultViewModel = CreateDownloadFailedResult(viewModelService, installerViewModel, exception);
                    installationResultDialogModel.InstallationResults.Add(failedResultViewModel);
                    currentInstallationViewModel.ProcessedInstallerFileCount++;
                    continue;
                }

                if (filterDuplicateInstallers && installedInstallerViewModels.Any(i => i.Name == installerViewModel.Name))
                {
                    Log.Info($"Installer \"{installerViewModel.FileName}\" with the same application name \"{installerViewModel.Name}\" already processed, file will be skipped.");
                    var skippedResultViewModel = CreateSkippedResult(viewModelService, installerViewModel);
                    installationResultDialogModel.InstallationResults.Add(skippedResultViewModel);
                    currentInstallationViewModel.ProcessedInstallerFileCount++;
                    continue;
                }

                var installationResultViewModel = await PerformOperation(
                    viewModelService,
                    installService,
                    notificationService,
                    installerViewModel,
                    currentInstallationViewModel,
                    succeededDownloadResult.TempFileName,
                    enableSilentInstallation,
                    disableReboot,
                    enableInstallationLogging,
                    logFolderPath);

                installedInstallerViewModels.Add(installerViewModel);
                installationResultDialogModel.InstallationResults.Add(installationResultViewModel);
                currentInstallationViewModel.ProcessedInstallerFileCount++;
            }

            currentInstallationViewModel.CurrentOperation = InstallationOperation.None;

            if (enableInstallationLogging && automaticallyDeleteInstallationLogs)
            {
                try
                {
                    RemoveOldestLogFiles(notificationService, uriService, logFolderPath, keepNewestInstallationLogs);
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception exception)
                {
                    Log.Warn("Deleting old log files failed", exception);
                }
#pragma warning restore CA1031 // Do not catch general exception types
            }

            installationResultDialogModel.IsReadOnly = true;
            return(installationResultDialogModel);
        }