コード例 #1
0
        public override async Task <int> ExecuteAsync(CommandContext context, CheckSettings settings)
        {
            Util.Verbose = settings.Verbose;
            Util.CI      = settings.CI;
            if (settings.CI)
            {
                settings.NonInteractive = true;
            }

            Console.Title = ToolInfo.ToolName;

            AnsiConsole.Render(
                new FigletText(".NET MAUI").LeftAligned().Color(Color.Green));

            AnsiConsole.MarkupLine($"[underline bold green]{Icon.Ambulance} {ToolInfo.ToolName} {Icon.Recommend}[/]");
            AnsiConsole.Render(new Rule());

            AnsiConsole.MarkupLine("This tool will attempt to evaluate your .NET MAUI development environment.");
            AnsiConsole.MarkupLine("If problems are detected, this tool may offer the option to try and fix them for you, or suggest a way to fix them yourself.");
            AnsiConsole.WriteLine();
            AnsiConsole.MarkupLine("Thanks for choosing .NET MAUI!");
            AnsiConsole.Render(new Rule());

            if (!Util.IsAdmin() && Util.IsWindows)
            {
                var suTxt = Util.IsWindows ? "Administrator" : "Superuser (su)";

                AnsiConsole.MarkupLine($"[bold red]{Icon.Bell} {suTxt} is required to fix most issues.  Consider exiting and running the tool with {suTxt} permissions.[/]");

                AnsiConsole.Render(new Rule());

                if (!settings.NonInteractive)
                {
                    if (!AnsiConsole.Confirm("Would you still like to continue?", false))
                    {
                        return(1);
                    }
                }
            }

            var cts = new System.Threading.CancellationTokenSource();

            var checkupStatus = new Dictionary <string, Models.Status>();
            var sharedState   = new SharedState();

            var results       = new Dictionary <string, DiagnosticResult>();
            var consoleStatus = AnsiConsole.Status();

            var skippedChecks = new List <string>();

            AnsiConsole.Markup($"[bold blue]{Icon.Thinking} Synchronizing configuration...[/]");

            var manifest = await ToolInfo.LoadManifest(settings.Manifest, settings.Dev);

            if (!ToolInfo.Validate(manifest))
            {
                ToolInfo.ExitPrompt(settings.NonInteractive);
                return(-1);
            }

            AnsiConsole.MarkupLine(" ok");
            AnsiConsole.Markup($"[bold blue]{Icon.Thinking} Scheduling appointments...[/]");

            if (!string.IsNullOrEmpty(settings.DotNetSdkRoot))
            {
                sharedState.SetEnvironmentVariable("DOTNET_ROOT", settings.DotNetSdkRoot);
            }

            var checkups = CheckupManager.BuildCheckupGraph(manifest, sharedState);

            AnsiConsole.MarkupLine(" ok");

            var checkupId = string.Empty;

            for (int i = 0; i < checkups.Count(); i++)
            {
                var checkup = checkups.ElementAt(i);

                // Set the manifest
                checkup.Manifest = manifest;

                // If the ID is the same, it's a retry
                var isRetry = checkupId == checkup.Id;

                // Track the last used id so we can detect retry
                checkupId = checkup.Id;

                if (!checkup.ShouldExamine(sharedState))
                {
                    checkupStatus[checkup.Id] = Models.Status.Ok;
                    continue;
                }

                var skipCheckup = false;

                var dependencies = checkup.DeclareDependencies(checkups.Select(c => c.Id));

                // Make sure our dependencies succeeded first
                if (dependencies?.Any() ?? false)
                {
                    foreach (var dep in dependencies)
                    {
                        var depCheckup = checkups.FirstOrDefault(c => c.Id.StartsWith(dep.CheckupId, StringComparison.OrdinalIgnoreCase));

                        if (depCheckup != null && depCheckup.IsPlatformSupported(Util.Platform))
                        {
                            if (!checkupStatus.TryGetValue(dep.CheckupId, out var depStatus) || depStatus == Models.Status.Error)
                            {
                                skipCheckup = dep.IsRequired;
                                break;
                            }
                        }
                    }
                }

                // See if --skip was specified
                if (settings.Skip?.Any(s => s.Equals(checkup.Id, StringComparison.OrdinalIgnoreCase) ||
                                       s.Equals(checkup.GetType().Name, StringComparison.OrdinalIgnoreCase)) ?? false)
                {
                    skipCheckup = true;
                }

                if (skipCheckup)
                {
                    skippedChecks.Add(checkup.Id);
                    checkupStatus[checkup.Id] = Models.Status.Error;
                    AnsiConsole.WriteLine();
                    AnsiConsole.MarkupLine($"[bold red]{Icon.Error} Skipped: " + checkup.Title + "[/]");
                    continue;
                }

                checkup.OnStatusUpdated += checkupStatusUpdated;

                AnsiConsole.WriteLine();
                AnsiConsole.MarkupLine($"[bold]{Icon.Checking} " + checkup.Title + " Checkup[/]...");
                Console.Title = checkup.Title;

                DiagnosticResult diagnosis = null;

                try
                {
                    diagnosis = await checkup.Examine(sharedState);
                }
                catch (Exception ex)
                {
                    Util.Exception(ex);
                    diagnosis = new DiagnosticResult(Models.Status.Error, checkup, ex.Message);
                }

                results[checkup.Id] = diagnosis;

                // Cache the status for dependencies
                checkupStatus[checkup.Id] = diagnosis.Status;

                if (diagnosis.Status == Models.Status.Ok)
                {
                    continue;
                }

                var statusEmoji = diagnosis.Status == Models.Status.Error ? Icon.Error : Icon.Warning;
                var statusColor = diagnosis.Status == Models.Status.Error ? "red" : "darkorange3_1";

                var msg = !string.IsNullOrEmpty(diagnosis.Message) ? " - " + diagnosis.Message : string.Empty;

                if (diagnosis.HasSuggestion)
                {
                    Console.WriteLine();
                    AnsiConsole.Render(new Rule());
                    AnsiConsole.MarkupLine($"[bold blue]{Icon.Recommend} Recommendation:[/][blue] {diagnosis.Suggestion.Name}[/]");

                    if (!string.IsNullOrEmpty(diagnosis.Suggestion.Description))
                    {
                        AnsiConsole.MarkupLine("" + diagnosis.Suggestion.Description + "");
                    }

                    AnsiConsole.Render(new Rule());
                    Console.WriteLine();

                    // See if we should fix
                    // needs to have a remedy available to even bother asking/trying
                    var doFix = diagnosis.Suggestion.HasSolution &&
                                (
                        // --fix + --non-interactive == auto fix, no prompt
                        (settings.NonInteractive && settings.Fix)
                        // interactive (default) + prompt/confirm they want to fix
                        || (!settings.NonInteractive && AnsiConsole.Confirm($"[bold]{Icon.Bell} Attempt to fix?[/]"))
                                );

                    if (doFix && !isRetry)
                    {
                        var isAdmin = Util.IsAdmin();

                        var adminMsg = Util.IsWindows ?
                                       $"{Icon.Bell} [red]Administrator Permissions Required.  Try opening a new console as Administrator and running this tool again.[/]"
                                                        : $"{Icon.Bell} [red]Super User Permissions Required.  Try running this tool again with 'sudo'.[/]";

                        var didFix = false;

                        foreach (var remedy in diagnosis.Suggestion.Solutions)
                        {
                            try
                            {
                                remedy.OnStatusUpdated += remedyStatusUpdated;

                                AnsiConsole.MarkupLine($"{Icon.Thinking} Attempting to fix: " + checkup.Title);

                                await remedy.Implement(sharedState, cts.Token);

                                didFix = true;
                                AnsiConsole.MarkupLine($"[bold]Fix applied.  Checking again...[/]");
                            }
                            catch (Exception x) when(x is AccessViolationException || x is UnauthorizedAccessException)
                            {
                                Util.Exception(x);
                                AnsiConsole.Markup(adminMsg);
                            }
                            catch (Exception ex)
                            {
                                Util.Exception(ex);
                                AnsiConsole.MarkupLine("[bold red]Fix failed - " + ex.Message + "[/]");
                            }
                            finally
                            {
                                remedy.OnStatusUpdated -= remedyStatusUpdated;
                            }
                        }

                        // RETRY The check again
                        if (didFix)
                        {
                            i--;
                        }
                    }
                }

                checkup.OnStatusUpdated -= checkupStatusUpdated;
            }

            AnsiConsole.Render(new Rule());
            AnsiConsole.WriteLine();

            var erroredChecks = results.Values.Where(d => d.Status == Models.Status.Error && !skippedChecks.Contains(d.Checkup.Id));

            foreach (var ec in erroredChecks)
            {
                Util.Log($"Checkup had Error status: {ec.Checkup.Id}");
            }

            var hasErrors = erroredChecks.Any();

            if (hasErrors)
            {
                AnsiConsole.MarkupLine($"[bold red]{Icon.Bell} There were one or more problems detected.[/]");
                AnsiConsole.MarkupLine($"[bold red]Please review the errors and correct them and run {ToolInfo.ToolCommand} again.[/]");
            }
            else
            {
                AnsiConsole.MarkupLine($"[bold blue]{Icon.Success} Congratulations, everything looks great![/]");
            }

            Console.Title = ToolInfo.ToolName;

            ToolInfo.ExitPrompt(settings.NonInteractive);

            Util.Log($"Has Errors? {hasErrors}");
            var exitCode = hasErrors ? 1 : 0;

            Environment.ExitCode = exitCode;

            return(exitCode);
        }