public override Task <DiagnosticResult> Examine(SharedState history) { var xamJdks = new List <OpenJdkInfo>(); try { var xamSdkInfo = new AndroidSdkInfo((traceLevel, msg) => Util.Log(msg), null, null, null); if (!string.IsNullOrEmpty(xamSdkInfo.JavaSdkPath)) { SearchDirectoryForJdks(xamJdks, xamSdkInfo.JavaSdkPath); } } catch (Exception ex) { Util.Exception(ex); } var jdks = xamJdks.Concat(FindJdks()) .GroupBy(j => j.Directory.FullName) .Select(g => g.First()); var ok = false; foreach (var jdk in jdks) { if ((jdk.JavaC.FullName.Contains("microsoft", StringComparison.OrdinalIgnoreCase) || jdk.JavaC.FullName.Contains("openjdk", StringComparison.OrdinalIgnoreCase)) && jdk.Version.IsCompatible(Version, RequireExact ? Version : null)) { ok = true; ReportStatus($"{jdk.Version} ({jdk.Directory})", Status.Ok); history.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName); // Try and set the global env var on windows if it's not set if (Util.IsWindows && string.IsNullOrEmpty(Environment.GetEnvironmentVariable("JAVA_HOME"))) { try { Environment.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName, EnvironmentVariableTarget.Machine); ReportStatus($"Set Environment Variable: JAVA_HOME={jdk.Directory.FullName}", Status.Ok); } catch { } } } else { ReportStatus($"{jdk.Version} ({jdk.Directory.FullName})", null); } } if (ok) { return(Task.FromResult(DiagnosticResult.Ok(this))); } return(Task.FromResult(new DiagnosticResult(Status.Error, this, new Suggestion("Install OpenJDK11", new BootsSolution(Manifest?.Check?.OpenJdk?.Url, "Download and Install Microsoft OpenJDK 11"))))); }
public override Task <DiagnosticResult> Examine(SharedState history) { var xamJdks = new List <OpenJdkInfo>(); try { var xamSdkInfo = new AndroidSdkInfo((traceLevel, msg) => Util.Log(msg), null, null, null); if (!string.IsNullOrEmpty(xamSdkInfo.JavaSdkPath)) { SearchDirectoryForJdks(xamJdks, xamSdkInfo.JavaSdkPath); } } catch (Exception ex) { Util.Exception(ex); } var jdks = xamJdks.Concat(FindJdks()); var ok = false; foreach (var jdk in jdks) { if ((jdk.JavaC.FullName.Contains("microsoft") || jdk.JavaC.FullName.Contains("openjdk")) && jdk.Version.IsCompatible(MinimumVersion, ExactVersion)) { ok = true; ReportStatus($"{jdk.Version} ({jdk.Directory})", Status.Ok); history.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName); // Try and set the global env var on windows if it's not set if (Util.IsWindows && string.IsNullOrEmpty(Environment.GetEnvironmentVariable("JAVA_HOME"))) { try { Environment.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName, EnvironmentVariableTarget.Machine); ReportStatus($"Set Environemnt Variable: JAVA_HOME={jdk.Directory.FullName}", Status.Ok); } catch { } } } else { ReportStatus($"{jdk.Version} ({jdk.Directory})", null); } } if (ok) { return(Task.FromResult(DiagnosticResult.Ok(this))); } return(Task.FromResult(new DiagnosticResult(Status.Error, this))); }
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); }
public DotNetSdk(SharedState sharedState) { KnownDotnetLocations = Util.Platform switch { Platform.Windows => new string[] { Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "dotnet", DotNetExeName), Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "dotnet", DotNetExeName), }, Platform.OSX => new string[] { "/usr/local/share/dotnet/dotnet", }, Platform.Linux => new string[] { // /home/user/share/dotnet/dotnet Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "share", "dotnet", DotNetExeName) }, _ => new string[] { } }; string sdkRoot = null; if (sharedState != null && sharedState.TryGetEnvironmentVariable("DOTNET_ROOT", out var envSdkRoot)) { if (Directory.Exists(envSdkRoot)) { sdkRoot = envSdkRoot; } } if (string.IsNullOrEmpty(sdkRoot) || !Directory.Exists(sdkRoot)) { sdkRoot = Microsoft.DotNet.NativeWrapper.EnvironmentProvider.GetDotnetExeDirectory(); } if (string.IsNullOrEmpty(sdkRoot) || !Directory.Exists(sdkRoot)) { var l = FindDotNetLocations(); if (l != default) { sdkRoot = l.sdkDir.FullName; } } sharedState.SetEnvironmentVariable("DOTNET_ROOT", sdkRoot); // First try and use the actual resolver logic DotNetSdkLocation = new DirectoryInfo(sdkRoot); DotNetExeLocation = new FileInfo(Path.Combine(DotNetSdkLocation.FullName, DotNetExeName)); }
public override async Task <DiagnosticResult> Examine(SharedState history) { var dn = new DotNetSdk(history); var missingDiagnosis = new DiagnosticResult(Status.Error, this, new Suggestion(".NET SDK not installed")); if (!dn.Exists) { return(missingDiagnosis); } var sdks = await dn.GetSdks(); var missingSdks = new List <Manifest.DotNetSdk>(); var sentinelFiles = new List <string>(); if (RequiredSdks?.Any() ?? false) { foreach (var rs in RequiredSdks) { var rsVersion = NuGetVersion.Parse(rs.Version); if (!sdks.Any(s => (rs.RequireExact && s.Version == rsVersion) || (!rs.RequireExact && s.Version >= rsVersion))) { missingSdks.Add(rs); } } } DotNetSdkInfo bestSdk = null; foreach (var sdk in sdks) { // See if the sdk is one of the required sdk's var requiredSdk = RequiredSdks.FirstOrDefault(rs => sdk.Version == NuGetVersion.Parse(rs.Version)); if (requiredSdk != null) { if (bestSdk == null || sdk.Version > bestSdk.Version) { bestSdk = sdk; } if (requiredSdk.EnableWorkloadResolver) { var sentinelPath = Path.Combine(sdk.Directory.FullName, "EnableWorkloadResolver.sentinel"); sentinelFiles.Add(sentinelPath); } ReportStatus($"{sdk.Version} - {sdk.Directory}", Status.Ok); } else { ReportStatus($"{sdk.Version} - {sdk.Directory}", null); } } // If we didn't get the exact one before, let's find a new enough one if (bestSdk == null) { bestSdk = sdks.OrderByDescending(s => s.Version)?.FirstOrDefault(); } // Find newest compatible sdk if (bestSdk != null) { history.SetEnvironmentVariable("DOTNET_SDK", bestSdk.Directory.FullName); history.SetEnvironmentVariable("DOTNET_SDK_VERSION", bestSdk.Version.ToString()); } // Add sentinel files that should be considered if (sentinelFiles.Any()) { history.ContributeState(this, "sentinel_files", sentinelFiles.ToArray()); } if (missingSdks.Any()) { var str = SdkListToString(); var remedies = new List <Solution>(); if (Util.CI) { remedies.AddRange(missingSdks .Select(ms => new DotNetSdkScriptInstallSolution(ms.Version))); } else { remedies.AddRange(missingSdks .Where(ms => !ms.Url.AbsolutePath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) .Select(ms => new BootsSolution(ms.Url, ".NET SDK " + ms.Version) as Solution)); remedies.AddRange(missingSdks .Where(ms => ms.Url.AbsolutePath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) .Select(ms => new MsInstallerSolution(ms.Url, ".NET SDK " + ms.Version))); } return(new DiagnosticResult(Status.Error, this, $".NET SDK {str} not installed.", new Suggestion($"Download .NET SDK {str}", remedies.ToArray()))); } return(new DiagnosticResult(Status.Ok, this)); }
public override Task <DiagnosticResult> Examine(SharedState history) { var jdkPath = history.GetEnvironmentVariable("JAVA_HOME") ?? Environment.GetEnvironmentVariable("JAVA_HOME"); string androidSdkPath = null; try { // Set the logger to override the default one that is set in this library // So we can catch output from failed path lookups that are otherwise swallowed var _ = new AndroidSdkInfo((traceLevel, msg) => { if (Util.Verbose || traceLevel == System.Diagnostics.TraceLevel.Error) { Util.LogAlways(msg); } }, androidSdkPath, null, jdkPath); } catch (Exception ex) { Util.Exception(ex); } if (string.IsNullOrEmpty(androidSdkPath)) { androidSdkPath = FindBestSdkLocation(); } var missingPackages = new List <IAndroidComponent>(); var installer = new AndroidSDKInstaller(new Helper(), AndroidManifestType.GoogleV2); installer.Discover(new List <string> { androidSdkPath }); var sdkInstance = installer.FindInstance(androidSdkPath); if (string.IsNullOrEmpty(sdkInstance?.Path)) { return(Task.FromResult( new DiagnosticResult( Status.Error, this, "Failed to find Android SDK.", new Suggestion("Install the Android SDK", "For more information see: [underline]https://aka.ms/dotnet-androidsdk-help[/]")))); } history.SetEnvironmentVariable("ANDROID_SDK_ROOT", sdkInstance.Path); history.SetEnvironmentVariable("ANDROID_HOME", sdkInstance.Path); var installed = sdkInstance?.Components?.AllInstalled(true); foreach (var package in RequiredPackages) { var v = !string.IsNullOrWhiteSpace(package.Version) ? new AndroidRevision(package.Version) : null; var installedPkg = FindInstalledPackage(installed, package) ?? FindInstalledPackage(installed, package.Alternatives?.ToArray()); if (installedPkg == null) { var pkgToInstall = sdkInstance?.Components?.AllNotInstalled()? .FirstOrDefault(p => p.Path.Equals(package.Path.Trim(), StringComparison.OrdinalIgnoreCase) && p.Revision >= (v ?? p.Revision)); ReportStatus($"{package.Path} ({package.Version}) missing.", Status.Error); if (pkgToInstall != null) { missingPackages.Add(pkgToInstall); } } else { if (!package.Path.Equals(installedPkg.Path) || v != (installedPkg.Revision ?? installedPkg.InstalledRevision)) { ReportStatus($"{installedPkg.Path} ({installedPkg.InstalledRevision ?? installedPkg.Revision})", Status.Ok); } else { ReportStatus($"{package.Path} ({package.Version})", Status.Ok); } } } if (!missingPackages.Any()) { return(Task.FromResult(DiagnosticResult.Ok(this))); } var installationSet = installer.GetInstallationSet(sdkInstance, missingPackages); var desc = @$ "Your Android SDK has missing or outdated packages. You can use the Android SDK Manager to install / update them. For more information see: [underline]https://aka.ms/dotnet-androidsdk-help[/]";