Пример #1
0
        private async Task <IProject> GetProjectAsync(IUpgradeContext context, CancellationToken token)
        {
            const string SelectProjectQuestion = "Here is the recommended order to upgrade. Select enter to follow this list, or input the project you want to start with.";

            if (_orderedProjects is null)
            {
                throw new UpgradeException("Project selection step must be initialized before it is applied (null _orderedProjects)");
            }

            // No need for an IAsyncEnumerable here since the commands shouldn't be displayed until
            // all are available anyhow.
            var commands = new List <ProjectCommand>();

            foreach (var project in _orderedProjects)
            {
                commands.Add(await CreateProjectCommandAsync(project).ConfigureAwait(false));
            }

            var result = await _input.ChooseAsync(SelectProjectQuestion, commands, token).ConfigureAwait(false);

            return(result.Project);

            async Task <ProjectCommand> CreateProjectCommandAsync(IProject project)
            {
                var projectCompleted = await IsCompletedAsync(context, project, token).ConfigureAwait(false);

                var checks = await RunChecksAsync(project, token).ConfigureAwait(false);

                return(new ProjectCommand(project, projectCompleted, checks));
            }
        }
Пример #2
0
        private async Task <string?> ChooseBackupPath(IUpgradeContext context, CancellationToken token)
        {
            var customPath = default(string);
            var commands   = new[]
            {
                UpgradeCommand.Create($"Use default path [{_backupPath}]"),
                UpgradeCommand.Create("Enter custom path", async(ctx, token) =>
                {
                    customPath = await _userInput.AskUserAsync("Please enter a custom path for backups:").ConfigureAwait(false);
                    return(!string.IsNullOrEmpty(customPath));
                })
            };

            while (!token.IsCancellationRequested)
            {
                var result = await _userInput.ChooseAsync("Please choose a backup path", commands, token).ConfigureAwait(false);

                if (await result.ExecuteAsync(context, token).ConfigureAwait(false))
                {
                    // customPath may be set in the lambda above.
#pragma warning disable CA1508 // Avoid dead conditional code
                    return(customPath ?? _backupPath);

#pragma warning restore CA1508 // Avoid dead conditional code
                }
            }

            return(null);
        }
Пример #3
0
        private async Task RunStepAsync(IUpgradeContext context, UpgradeStep step, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            await _io.Output.WriteLineAsync();

            var commands = _commandProvider.GetCommands(step, context);
            var command  = await _input.ChooseAsync("Choose a command:", commands, token);

            // TODO : It might be nice to allow commands to show more details by having a 'status' property
            //        that can be shown here. Also, commands currently only return bools but, in the future,
            //        if they return more complex objects, custom handlers could be used to respond to the different
            //        commands' return values.
            if (!await ExecuteAndTimeCommand(context, step, command, token))
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                await _io.Output.WriteAsync($"Command ({command.CommandText}) did not succeed");

                Console.ResetColor();
            }
            else if (!await _input.WaitToProceedAsync(token))
            {
                _logger.LogWarning("Upgrade process was canceled. Quitting....");
            }

            token.ThrowIfCancellationRequested();
        }
Пример #4
0
        public async Task RunAsync(CancellationToken token)
        {
            using var context = await _contextFactory.CreateContext(token);

            await _stateManager.LoadStateAsync(context, token);

            try
            {
                // Cache current steps here as defense-in-depth against the possibility
                // of a bug (or very weird upgrade step behavior) causing the current step
                // to reset state after being initialized by GetNextStepAsync
                var steps = await _upgrader.InitializeAsync(context, token);

                var step = await _upgrader.GetNextStepAsync(context, token);

                while (step is not null)
                {
                    while (!step.IsDone)
                    {
                        token.ThrowIfCancellationRequested();

                        ShowUpgradeSteps(steps, context, step);
                        _io.Output.WriteLine();

                        var commands = _commandProvider.GetCommands(step);
                        var command  = await _input.ChooseAsync("Choose a command:", commands, token);

                        // TODO : It might be nice to allow commands to show more details by having a 'status' property
                        //        that can be shown here. Also, commands currently only return bools but, in the future,
                        //        if they return more complex objects, custom handlers could be used to respond to the different
                        //        commands' return values.
                        if (!await command.ExecuteAsync(context, token))
                        {
                            Console.ForegroundColor = ConsoleColor.Yellow;
                            _io.Output.WriteLine($"Command ({command.CommandText}) did not succeed");
                            Console.ResetColor();
                        }
                        else if (await _input.WaitToProceedAsync(token))
                        {
                            ConsoleUtils.Clear();
                        }
                        else
                        {
                            _logger.LogWarning("Upgrade process was canceled. Quitting....");
                            return;
                        }
                    }

                    step = await _upgrader.GetNextStepAsync(context, token);
                }

                _logger.LogInformation("Upgrade has completed. Please review any changes.");
            }
            finally
            {
                // Do not pass the same token as it may have been canceled and we still need to persist this.
                await _stateManager.SaveStateAsync(context, default);
            }
        }
Пример #5
0
        private async ValueTask <IProject> GetEntrypointAsync(IUpgradeContext context, CancellationToken token)
        {
            const string EntrypointQuestion = "Please select the project you run. We will then analyze the dependencies and identify the recommended order to upgrade projects.";

            var allProjects = context.Projects.OrderBy(p => p.GetRoslynProject().Name).Select(ProjectCommand.Create).ToList();
            var result      = await _userInput.ChooseAsync(EntrypointQuestion, allProjects, token).ConfigureAwait(false);

            return(result.Project);
        }
        public override async Task <bool> ExecuteAsync(IUpgradeContext context, CancellationToken token)
        {
            var target = await _userInput.ChooseAsync("Choose log target:", CreateFromEnum <LogTarget>(), token);

            var result = await _userInput.ChooseAsync("Choose your log level:", CreateFromEnum <LogLevel>(), token);

            switch (target.Value)
            {
            case LogTarget.Console:
                _logSettings.SetConsoleLevel(result.Value);
                return(true);

            case LogTarget.File:
                _logSettings.SetFileLevel(result.Value);
                return(true);

            default:
                return(false);
            }
        }
        private async Task <IProject> GetProject(IUpgradeContext context, Func <IUpgradeContext, IProject, bool> isProjectCompleted, CancellationToken token)
        {
            const string SelectProjectQuestion = "Here is the recommended order to upgrade. Select enter to follow this list, or input the project you want to start with.";

            if (context.EntryPoint is null)
            {
                throw new InvalidOperationException("Entrypoint must be set before using this step");
            }

            var ordered = context.EntryPoint.PostOrderTraversal(p => p.ProjectReferences).Select(CreateProjectCommand);

            var result = await _input.ChooseAsync(SelectProjectQuestion, ordered, token).ConfigureAwait(false);

            return(result.Project);

            ProjectCommand CreateProjectCommand(IProject project)
            {
                return(new ProjectCommand(project, isProjectCompleted(context, project)));
            }
        }