From fc13e3172cbb20624d1634a3ab8a4c83e2b85003 Mon Sep 17 00:00:00 2001 From: Bela VanderVoort Date: Fri, 8 Mar 2024 14:34:40 -0600 Subject: [PATCH] only use dotnetCoreRuntime, wait until rider is ready to ensure it is loaded. --- Src/CSharpier.Rider/CHANGELOG.md | 4 + .../intellij/csharpier/CSharpierStartup.java | 15 -- .../intellij/csharpier/CSharpierStartup.kt | 40 +++++ .../com/intellij/csharpier/DotNetFinder.java | 150 ------------------ .../intellij/csharpier/DotNetProvider.java | 23 +-- .../ReformatWithCSharpierAction.java | 1 + 6 files changed, 48 insertions(+), 185 deletions(-) delete mode 100644 Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.java create mode 100644 Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.kt delete mode 100644 Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetFinder.java diff --git a/Src/CSharpier.Rider/CHANGELOG.md b/Src/CSharpier.Rider/CHANGELOG.md index 2129582f6..81221c833 100644 --- a/Src/CSharpier.Rider/CHANGELOG.md +++ b/Src/CSharpier.Rider/CHANGELOG.md @@ -2,6 +2,10 @@ # csharpier-rider Changelog +## [1.6.2] +- Fix issues with lookup of '.NET CLI executable path', csharpier will now wait until rider is ready with the information. +- No more falling back to `PATH` + ## [1.6.1] - Delay lookup of '.NET CLI executable path' until it is needed - Fall back to looking for dotnet on PATH if '.NET CLI executable path' is not available diff --git a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.java b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.java deleted file mode 100644 index 67c639539..000000000 --- a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.intellij.csharpier; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupActivity; -import org.jetbrains.annotations.NotNull; - -public class CSharpierStartup implements StartupActivity, DumbAware { - @Override - public void runActivity(@NotNull Project project) { - CSharpierProcessProvider.getInstance(project); - ApplicationManager.getApplication().getService(ReformatWithCSharpierOnSave.class); - } -} diff --git a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.kt b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.kt new file mode 100644 index 000000000..50f773856 --- /dev/null +++ b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierStartup.kt @@ -0,0 +1,40 @@ +package com.intellij.csharpier + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.StartupActivity +import com.intellij.openapi.startup.StartupActivity.DumbAware +import com.jetbrains.rd.platform.util.lifetime +import com.jetbrains.rd.util.reactive.adviseUntil +import com.jetbrains.rider.model.riderSolutionLifecycle +import com.jetbrains.rider.projectView.solution +import com.jetbrains.rider.runtime.RiderDotNetActiveRuntimeHost + +// kotlin because I have no idea how to get project.solution.riderSolutionLifecycle.isProjectModelReady.adviseUntil happy in java +class CSharpierStartup : StartupActivity, DumbAware { + var logger: Logger = CSharpierLogger.getInstance() + + override fun runActivity(project: Project) { + project.solution.riderSolutionLifecycle.isProjectModelReady.adviseUntil(project.lifetime) { isReady -> + + val dotNetCoreRuntime = + RiderDotNetActiveRuntimeHost.Companion.getInstance(project).dotNetCoreRuntime.value + + if (!isReady || dotNetCoreRuntime == null) { + if (isReady) { + logger.warn("isProjectModelReady is true, but dotNetCoreRuntime is still null"); + } + + return@adviseUntil false + } + + CSharpierProcessProvider.getInstance(project) + ApplicationManager.getApplication().getService(ReformatWithCSharpierOnSave::class.java) + DotNetProvider.getInstance(project).initialize(); + + return@adviseUntil true + } + } + +} \ No newline at end of file diff --git a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetFinder.java b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetFinder.java deleted file mode 100644 index ccc04d72f..000000000 --- a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetFinder.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.intellij.csharpier; - -import com.intellij.openapi.diagnostic.Logger; -import org.apache.commons.lang.SystemUtils; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -public class DotNetFinder { - - public static String findOnPath(Logger logger) { - logger.debug("Trying to find dotnet on PATH using dotnet --info"); - - var env = Map.of( - "DOTNET_CLI_UI_LANGUAGE", "en-US", - "DOTNET_NOLOGO", "1", - "DOTNET_CLI_TELEMETRY_OPTOUT", "1", - "DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "1"); - var dotnetInfo = ProcessHelper.executeCommand(List.of("dotnet", "--info"), env, null); - if (dotnetInfo == null && !SystemUtils.IS_OS_WINDOWS) - { - logger.debug("Trying to find dotnet on PATH using sh -c dotnet --info"); - dotnetInfo = ProcessHelper.executeCommand(List.of("sh", "-c", "dotnet --info"), env, null); - } - if (dotnetInfo == null && SystemUtils.IS_OS_MAC) { - logger.debug("Trying to find dotnet on PATH using /bin/zsh -c dotnet --info"); - - // For Mac, the .NET binary isn't available for ProcessBuilder, so we'll add the default - // installation location to the PATH. We'll prefer the ARM version and fallback to the x64. - var path = System.getenv("PATH"); - path += ":/usr/local/share/dotnet:/usr/local/share/dotnet/x64/dotnet"; - env = new HashMap<>(env); - env.put("PATH", path); - dotnetInfo = ProcessHelper.executeCommand(List.of("/bin/zsh", "-c", "dotnet --info"), env, null); - } - - if (dotnetInfo == null) { - return null; - } - - String version = null; - - var lines = dotnetInfo.split("\\r?\\n"); - for (var line : lines) { - var pattern = Pattern.compile("^\\s*Version:\\s*([^\\s].*)$"); - var matcher = pattern.matcher(line); - - if (matcher.find()) { - version = matcher.group(1); - } - } - - if (version == null) { - return null; - } - - var runtimesOutput = ProcessHelper.executeCommand(List.of("dotnet", "--list-runtimes"), env, null); - var runtimeVersions = new HashMap>(); - lines = runtimesOutput.split("\\r?\\n"); - for (var line : lines) { - var pattern = Pattern.compile("^([\\w.]+) ([^ ]+) \\[([^\\]]+)\\]$"); - var matcher = pattern.matcher(line); - - if (matcher.find()) { - var runtime = matcher.group(1); - var runtimeVersion = matcher.group(2); - var path = matcher.group(3); - - if (!runtimeVersions.containsKey(runtime)) { - var versions = new ArrayList(); - runtimeVersions.put(runtime, versions); - } - - var runtimeInfo = new RuntimeInfo(); - runtimeInfo.Version = runtimeVersion; - runtimeInfo.Path = path; - runtimeVersions.get(runtime).add(runtimeInfo); - } - } - - return findDotNetFromRuntimes(runtimeVersions, logger); - } - - private static String findDotNetFromRuntimes(HashMap> runtimes, Logger logger) { - var requiredRuntimeVersion = "6.0.0"; - - var coreRuntimeVersions = runtimes.get("Microsoft.NETCore.App"); - RuntimeInfo matchingRuntime = null; - for (var runtime : coreRuntimeVersions) { - // We consider a match if the runtime is greater than or equal to the required version since we roll forward. - if (compareVersions(runtime.Version, requiredRuntimeVersion) > 0) { - logger.debug("Using " + runtime.Path + " with version " + runtime.Version); - matchingRuntime = runtime; - break; - } - } - - if (matchingRuntime == null) { - return null; - } - - // The .NET install layout is a well known structure on all platforms. - // See https://github.com/dotnet/designs/blob/main/accepted/2020/install-locations.md#net-core-install-layout - // - // Therefore we know that the runtime path is always in /shared/ - // and the dotnet executable is always at /dotnet(.exe). - // - // Since dotnet --list-runtimes will always use the real assembly path to output the runtime folder (no symlinks!) - // we know the dotnet executable will be two folders up in the install root. - var runtimeFolderPath = matchingRuntime.Path; - var installFolder = Paths.get(runtimeFolderPath).getParent().getParent().toString(); - var dotnetExecutablePath = Paths.get(installFolder, System.getProperty("os.name").contains("Windows") ? "dotnet.exe" : "dotnet").toString(); - - if (!Files.exists(Paths.get(dotnetExecutablePath))) { - throw new RuntimeException(String.format("dotnet executable path does not exist: %s, dotnet installation may be corrupt.", dotnetExecutablePath)); - } - - return dotnetExecutablePath; - } - - private static int compareVersions(String version1, String version2) { - String[] parts1 = version1.split("\\."); - String[] parts2 = version2.split("\\."); - - int minLength = Math.min(parts1.length, parts2.length); - - for (int i = 0; i < minLength; i++) { - int part1 = Integer.parseInt(parts1[i]); - int part2 = Integer.parseInt(parts2[i]); - - if (part1 < part2) { - return -1; - } else if (part1 > part2) { - return 1; - } - } - - return Integer.compare(parts1.length, parts2.length); - } -} - -class RuntimeInfo { - public String Version; - public String Path; -} diff --git a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetProvider.java b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetProvider.java index 19523c97d..89aeff351 100644 --- a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetProvider.java +++ b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/DotNetProvider.java @@ -16,7 +16,6 @@ public class DotNetProvider { private final Project project; private String dotNetRoot; private String cliExePath; - private boolean isInitialized; public DotNetProvider(@NotNull Project project) { this.project = project; @@ -26,11 +25,7 @@ static DotNetProvider getInstance(@NotNull Project project) { return project.getService(DotNetProvider.class); } - private synchronized void initializeIfNeeded() { - if (this.isInitialized) { - return; - } - + void initialize() { var foundDotNet = this.findDotNet(); if (!foundDotNet) { @@ -39,26 +34,17 @@ private synchronized void initializeIfNeeded() { var notification = NotificationGroupManager.getInstance().getNotificationGroup("CSharpier").createNotification(title, message, NotificationType.WARNING); notification.notify(this.project); } - - this.isInitialized = true; } private boolean findDotNet() { try { var dotNetCoreRuntime = RiderDotNetActiveRuntimeHost.Companion.getInstance(project).getDotNetCoreRuntime().getValue(); - if (!CSharpierSettings.getInstance(this.project).getSkipCliExePath() - && dotNetCoreRuntime != null - && dotNetCoreRuntime.getCliExePath() != null) { + if (dotNetCoreRuntime != null && dotNetCoreRuntime.getCliExePath() != null) { this.logger.debug("Using dotnet found from RiderDotNetActiveRuntimeHost at " + dotNetCoreRuntime.getCliExePath()); this.cliExePath = dotNetCoreRuntime.getCliExePath(); } else { - this.cliExePath = DotNetFinder.findOnPath(this.logger); - - if (this.cliExePath == null) { - return false; - } - this.logger.debug("Found dotnet at " + this.cliExePath); + return false; } this.dotNetRoot = Paths.get(this.cliExePath).getParent().toString(); @@ -72,7 +58,6 @@ private boolean findDotNet() { } public String execDotNet(List command, File workingDirectory) { - this.initializeIfNeeded(); var commands = new ArrayList<>(command); commands.add(0, this.cliExePath); @@ -82,12 +67,10 @@ public String execDotNet(List command, File workingDirectory) { } public String getDotNetRoot() { - this.initializeIfNeeded(); return this.dotNetRoot; } public boolean foundDotNet() { - this.initializeIfNeeded(); return this.cliExePath != null; } diff --git a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierAction.java b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierAction.java index 794a48afb..518d6321a 100644 --- a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierAction.java +++ b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierAction.java @@ -27,6 +27,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { @Override public void update(@NotNull AnActionEvent e) { + logger.info("update!"); var virtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE); if (virtualFile == null) { e.getPresentation().setVisible(false);