diff --git a/java/idea-ui/intellij.java.ui.iml b/java/idea-ui/intellij.java.ui.iml
index 005ecd451f91..abb03b9688a8 100644
--- a/java/idea-ui/intellij.java.ui.iml
+++ b/java/idea-ui/intellij.java.ui.iml
@@ -34,5 +34,7 @@
+
+
\ No newline at end of file
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/EelSdkFilter.kt b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/EelSdkFilter.kt
new file mode 100644
index 000000000000..5eaa6e7f4e6b
--- /dev/null
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/EelSdkFilter.kt
@@ -0,0 +1,24 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+@file:JvmName("EelSdkFilter")
+
+package com.intellij.openapi.roots.ui.configuration
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.projectRoots.Sdk
+import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel
+import com.intellij.platform.eel.provider.getEelApiKey
+import java.util.function.Predicate
+
+internal fun filterSdkByEel(project: Project): Predicate {
+ val eelApiKey = project.getEelApiKey()
+ return Predicate { sdk ->
+ ProjectSdksModel.sdkMatchesEel(eelApiKey, sdk)
+ }
+}
+
+internal fun filterSdkSuggestionByEel(project: Project): Predicate {
+ val eelApiKey = project.getEelApiKey()
+ return Predicate { item ->
+ ProjectSdksModel.sdkMatchesEel(eelApiKey, item.homePath)
+ }
+}
\ No newline at end of file
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java
index bbf34073fd4c..511a190f71a3 100644
--- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleJdkConfigurable.java
@@ -76,6 +76,7 @@ public abstract class ModuleJdkConfigurable implements Disposable {
final Project project = getRootModel().getModule().getProject();
Predicate predicate = SimpleJavaSdkType.notSimpleJavaSdkType();
+ // TODO Use EelApi here.
myCbModuleJdk = new JdkComboBox(project, myJdksModel, predicate::test,
WslSdkFilter.filterSdkByWsl(project), WslSdkFilter.filterSdkSuggestionByWsl(project),
null, jdk -> {
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurableUi.kt b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurableUi.kt
index 87a7dd89b7f5..cd4507891a3e 100644
--- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurableUi.kt
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdkConfigurableUi.kt
@@ -5,6 +5,7 @@ import com.intellij.openapi.application.ApplicationBundle
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.SimpleJavaSdkType
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel
+import com.intellij.openapi.util.registry.Registry
import com.intellij.ui.dsl.builder.AlignX
import com.intellij.ui.dsl.builder.panel
import javax.swing.JButton
@@ -16,13 +17,21 @@ internal class ProjectJdkConfigurableUi {
fun panel(project: Project, jdkModel: ProjectSdksModel): JPanel = panel {
row {
- jdkComboBox = cell(
+ val component = if (Registry.`is`("java.home.finder.use.eel"))
+ JdkComboBox.createCombobox(project,
+ jdkModel,
+ SimpleJavaSdkType.notSimpleJavaSdkType(),
+ filterSdkByEel(project),
+ filterSdkSuggestionByEel(project),
+ null)
+ else
JdkComboBox.createCombobox(project,
jdkModel,
SimpleJavaSdkType.notSimpleJavaSdkType(),
WslSdkFilter.filterSdkByWsl(project),
WslSdkFilter.filterSdkSuggestionByWsl(project),
- null))
+ null)
+ jdkComboBox = cell(component)
.resizableColumn()
.align(AlignX.FILL)
.component
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java
index cad02aec9ee2..856e4016b482 100644
--- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java
@@ -44,10 +44,12 @@ import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.NioFiles;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
+import com.intellij.platform.eel.provider.EelApiKey;
import com.intellij.ui.navigation.Place;
import com.intellij.util.PlatformIcons;
import com.intellij.util.concurrency.ThreadingAssertions;
@@ -67,6 +69,8 @@ import java.nio.file.Paths;
import java.util.*;
import java.util.function.Predicate;
+import static com.intellij.platform.eel.provider.EelProviderUtil.getEelApiKey;
+
public class ModuleStructureConfigurable extends BaseStructureConfigurable implements Place.Navigator, Configurable.WithEpDependencies {
private static final Comparator NODE_COMPARATOR = (o1, o2) -> {
final NamedConfigurable> configurable1 = o1.getConfigurable();
@@ -572,8 +576,9 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple
modules = myContext.myModulesConfigurator.addNewModule(basePath);
}
if (modules != null && !modules.isEmpty()) {
+ EelApiKey eelKey = Registry.is("java.home.finder.use.eel") ? getEelApiKey(myProject) : null;
//new module wizard may add yet another SDK to the project
- myProjectStructureConfigurable.getProjectJdksModel().syncSdks();
+ myProjectStructureConfigurable.getProjectJdksModel().syncSdks(eelKey);
for (Module module : modules) {
addModuleNode(module);
}
diff --git a/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/CommonLogicForOnboardingTours.kt b/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/CommonLogicForOnboardingTours.kt
index 0b72de7836c7..25b633215285 100644
--- a/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/CommonLogicForOnboardingTours.kt
+++ b/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/CommonLogicForOnboardingTours.kt
@@ -49,7 +49,6 @@ import training.dsl.LessonUtil.restoreIfModifiedOrMoved
import training.dsl.LessonUtil.restorePopupPosition
import training.learn.LessonsBundle
import training.learn.course.KLesson
-import training.learn.course.LessonProperties
import training.learn.lesson.general.run.clearBreakpoints
import training.learn.lesson.general.run.toggleBreakpointTask
import training.ui.LearningUiHighlightingManager
@@ -357,7 +356,7 @@ abstract class CommonLogicForOnboardingTours(id: String, @Nls lessonName: String
val jdkVersionsFuture = CompletableFuture>()
runBackgroundableTask(ProjectBundle.message("progress.title.detecting.sdks"), project, false) { indicator ->
val jdkVersions = mutableListOf()
- SdkDetector.getInstance().detectSdks(JavaSdk.getInstance(), indicator, object : SdkDetector.DetectedSdkListener {
+ SdkDetector.getInstance().detectSdks(project, JavaSdk.getInstance(), indicator, object : SdkDetector.DetectedSdkListener {
override fun onSdkDetected(type: SdkType, version: String, home: String) {
jdkVersions.add(version)
}
diff --git a/java/java-impl/intellij.java.impl.iml b/java/java-impl/intellij.java.impl.iml
index 736ed95cbd5f..f9818c146754 100644
--- a/java/java-impl/intellij.java.impl.iml
+++ b/java/java-impl/intellij.java.impl.iml
@@ -80,6 +80,8 @@
+
+
diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/ExistingJdkConfigurationActivity.kt b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/ExistingJdkConfigurationActivity.kt
index 6b82b408dd1d..3a26677237a3 100644
--- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/ExistingJdkConfigurationActivity.kt
+++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/ExistingJdkConfigurationActivity.kt
@@ -42,7 +42,7 @@ private class ExistingJdkConfigurationActivity : ProjectActivity {
val rootManager = project.serviceAsync()
val addedJdks = registeredJdks.toMutableList()
- val priorityPaths = JavaHomeFinder.getFinder().findInJavaHome()
+ val priorityPaths = JavaHomeFinder.getFinder(project).findInJavaHome()
writeAction {
// Register collected JDKs
diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java
index 2e92f97f0190..13d3878bcc7e 100644
--- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java
+++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java
@@ -13,6 +13,7 @@ import com.intellij.openapi.extensions.ExtensionPointUtil;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.roots.AnnotationOrderRootType;
@@ -33,6 +34,7 @@ import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
+import com.intellij.platform.eel.provider.EelProviderUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.PathUtil;
import com.intellij.util.concurrency.AppExecutorUtil;
@@ -189,7 +191,12 @@ public final class JavaSdkImpl extends JavaSdk {
@Override
public @NotNull Collection suggestHomePaths() {
- return JavaHomeFinder.suggestHomePaths();
+ return suggestHomePaths(null);
+ }
+
+ @Override
+ public @NotNull Collection suggestHomePaths(@Nullable Project project) {
+ return JavaHomeFinder.suggestHomePaths(EelProviderUtil.getEelApiBlocking(project), false);
}
@Override
diff --git a/platform/lang-core/api-dump.txt b/platform/lang-core/api-dump.txt
index f4b05f5400c1..a1e71af67a22 100644
--- a/platform/lang-core/api-dump.txt
+++ b/platform/lang-core/api-dump.txt
@@ -475,7 +475,8 @@ f:com.intellij.openapi.projectRoots.JdkCommandLineSetup$Companion
com.intellij.openapi.projectRoots.JdkFinder
- a:defaultJavaLocation():java.lang.String
- s:getInstance():com.intellij.openapi.projectRoots.JdkFinder
-- a:suggestHomePaths():java.util.List
+- suggestHomePaths():java.util.List
+- a:suggestHomePaths(com.intellij.openapi.project.Project):java.util.List
f:com.intellij.openapi.projectRoots.JdkUtil
- sf:AGENT_RUNTIME_CLASSPATH:com.intellij.openapi.util.Key
- sf:COMMAND_LINE_CONTENT:com.intellij.openapi.util.Key
@@ -548,6 +549,7 @@ a:com.intellij.openapi.projectRoots.SdkType
- showCustomCreateUI(com.intellij.openapi.projectRoots.SdkModel,javax.swing.JComponent,com.intellij.openapi.projectRoots.Sdk,com.intellij.util.Consumer):V
- a:suggestHomePath():java.lang.String
- suggestHomePaths():java.util.Collection
+- suggestHomePaths(com.intellij.openapi.project.Project):java.util.Collection
- a:suggestSdkName(java.lang.String,java.lang.String):java.lang.String
- supportsCustomCreateUI():Z
c:com.intellij.openapi.projectRoots.SimpleJavaSdkType
@@ -570,6 +572,7 @@ c:com.intellij.openapi.projectRoots.SimpleJavaSdkType
- saveAdditionalData(com.intellij.openapi.projectRoots.SdkAdditionalData,org.jdom.Element):V
- suggestHomePath():java.lang.String
- suggestHomePaths():java.util.Collection
+- suggestHomePaths(com.intellij.openapi.project.Project):java.util.Collection
- suggestSdkName(java.lang.String,java.lang.String):java.lang.String
- versionStringComparator():java.util.Comparator
f:com.intellij.openapi.projectRoots.impl.SdkVersionUtil
diff --git a/platform/lang-core/src/com/intellij/openapi/projectRoots/JdkFinder.java b/platform/lang-core/src/com/intellij/openapi/projectRoots/JdkFinder.java
index 800b00864328..10b0dc9650cd 100644
--- a/platform/lang-core/src/com/intellij/openapi/projectRoots/JdkFinder.java
+++ b/platform/lang-core/src/com/intellij/openapi/projectRoots/JdkFinder.java
@@ -2,6 +2,7 @@
package com.intellij.openapi.projectRoots;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -24,7 +25,25 @@ public interface JdkFinder {
* If no JDK found, returns possible folders to start file chooser.
* The method is heavy, it is not recommended to run it from EDT thread.
* @return suggested sdk home paths (sorted)
+ *
+ * @deprecated Consider using {@link JdkFinder#suggestHomePaths(Project)}.
+ * The JDK should be searched on the machine where the project is located,
+ * not where the IDE is running.
*/
@NotNull
- List suggestHomePaths();
+ @Deprecated
+ default List<@NotNull String> suggestHomePaths() {
+ return suggestHomePaths(null);
+ }
+
+ /**
+ * Tries to find existing Java SDKs on the computer that contains {@code project}.
+ * If no JDK found, returns possible folders to start file chooser.
+ * The method is heavy, it is not recommended to run it from EDT thread.
+ *
+ * @param project the project for which JDK should be suggested, or {@code null} if JDK should be searched locally
+ * @return suggested sdk home paths (sorted)
+ */
+ @NotNull
+ List<@NotNull String> suggestHomePaths(@Nullable Project project);
}
diff --git a/platform/lang-core/src/com/intellij/openapi/projectRoots/SdkType.java b/platform/lang-core/src/com/intellij/openapi/projectRoots/SdkType.java
index 0f1538f8dae3..334c289f5cff 100644
--- a/platform/lang-core/src/com/intellij/openapi/projectRoots/SdkType.java
+++ b/platform/lang-core/src/com/intellij/openapi/projectRoots/SdkType.java
@@ -24,6 +24,7 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.List;
+
/**
* Inherit from this class and register implementation as {@code sdkType} extension in plugin.xml to provide a custom type of
* SDK. Users can create and assign SDKs to modules in Project Structure dialog.
@@ -63,12 +64,28 @@ public abstract class SdkType implements SdkTypeId {
* for possible interruption request. It is not recommended to call this method from a ETD thread. See
* an alternative {@link #suggestHomePath()} method for EDT-friendly calls.
* @see #suggestHomePath()
+ *
+ * @deprecated Use {@link #suggestHomePaths(Project)}
*/
+ @Deprecated
public @NotNull Collection suggestHomePaths() {
String home = suggestHomePath();
return ContainerUtil.createMaybeSingletonList(home);
}
+ /**
+ * Returns a list of all valid SDKs found on the host where {@code project} is located.
+ *
+ * E.g. for Python SDK on Unix the method may return {@code ["/usr/bin/python2", "/usr/bin/python3"]}.
+ *
+ * This method may take significant time to execute. The implementation may check {@link ProgressManager#checkCanceled()}
+ * for possible interruption request. It is not recommended to call this method from a ETD thread. See
+ * an alternative {@link #suggestHomePath()} method for EDT-friendly calls.
+ */
+ public @NotNull Collection suggestHomePaths(@Nullable Project project) {
+ return suggestHomePaths();
+ }
+
/**
* This method is used to decide if a given {@link VirtualFile} has something in common
* with this {@link SdkType}.
diff --git a/platform/lang-core/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java b/platform/lang-core/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java
index 14043e83cd46..4276765268ca 100644
--- a/platform/lang-core/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java
+++ b/platform/lang-core/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java
@@ -1,8 +1,7 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.projectRoots;
-import com.intellij.openapi.application.Application;
-import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.projectRoots.impl.SdkVersionUtil;
import com.intellij.openapi.util.Comparing;
@@ -80,12 +79,17 @@ public class SimpleJavaSdkType extends SdkType implements JavaSdkType {
@Override
public @NotNull Collection suggestHomePaths() {
+ return suggestHomePaths(null);
+ }
+
+ @Override
+ public @NotNull Collection suggestHomePaths(@Nullable Project project) {
//there is no need to search for JDKs if there is JavaSdkImpl registered
if (!notSimpleJavaSdkTypeIfAlternativeExists().test(this)) {
return Collections.emptyList();
}
- return JdkFinder.getInstance().suggestHomePaths();
+ return JdkFinder.getInstance().suggestHomePaths(project);
}
@Override
diff --git a/platform/lang-impl/api-dump-unreviewed.txt b/platform/lang-impl/api-dump-unreviewed.txt
index 7bacd02ea4e8..6f9a31574f27 100644
--- a/platform/lang-impl/api-dump-unreviewed.txt
+++ b/platform/lang-impl/api-dump-unreviewed.txt
@@ -14525,6 +14525,7 @@ f:com.intellij.openapi.roots.ui.configuration.SdkComboBoxModel$Companion
- bs:createSdkComboBoxModel$default(com.intellij.openapi.roots.ui.configuration.SdkComboBoxModel$Companion,com.intellij.openapi.project.Project,com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel,java.util.function.Predicate,java.util.function.Predicate,java.util.function.Predicate,I,java.lang.Object):com.intellij.openapi.roots.ui.configuration.SdkComboBoxModel
c:com.intellij.openapi.roots.ui.configuration.SdkDetector
- ():V
+- detectSdks(com.intellij.openapi.project.Project,com.intellij.openapi.projectRoots.SdkType,com.intellij.openapi.progress.ProgressIndicator,com.intellij.openapi.roots.ui.configuration.SdkDetector$DetectedSdkListener):V
- detectSdks(com.intellij.openapi.projectRoots.SdkType,com.intellij.openapi.progress.ProgressIndicator,com.intellij.openapi.roots.ui.configuration.SdkDetector$DetectedSdkListener):V
- getDetectedSdksWithUpdate(com.intellij.openapi.project.Project,com.intellij.openapi.Disposable,com.intellij.openapi.application.ModalityState,com.intellij.openapi.roots.ui.configuration.SdkDetector$DetectedSdkListener):V
- s:getInstance():com.intellij.openapi.roots.ui.configuration.SdkDetector
@@ -14821,7 +14822,6 @@ c:com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel
- doAdd(com.intellij.openapi.projectRoots.Sdk,java.util.function.Consumer):V
- doAdd(javax.swing.JComponent,com.intellij.openapi.projectRoots.Sdk,com.intellij.openapi.projectRoots.SdkType,com.intellij.util.Consumer):V
- doAdd(javax.swing.JComponent,com.intellij.openapi.projectRoots.SdkType,com.intellij.util.Consumer):V
-- doDownload(com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownload,javax.swing.JComponent,com.intellij.openapi.projectRoots.Sdk,com.intellij.openapi.projectRoots.SdkType,java.util.function.Consumer):V
- downloadSdk(com.intellij.openapi.projectRoots.Sdk):V
- findSdk(com.intellij.openapi.projectRoots.Sdk):com.intellij.openapi.projectRoots.Sdk
- findSdk(java.lang.String):com.intellij.openapi.projectRoots.Sdk
diff --git a/platform/lang-impl/intellij.platform.lang.impl.iml b/platform/lang-impl/intellij.platform.lang.impl.iml
index d43ceeb7d2be..3f54f6299caf 100644
--- a/platform/lang-impl/intellij.platform.lang.impl.iml
+++ b/platform/lang-impl/intellij.platform.lang.impl.iml
@@ -107,5 +107,7 @@
+
+
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinder.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinder.java
index e947f594648e..fbd57725ecd7 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinder.java
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinder.java
@@ -1,10 +1,12 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.projectRoots.impl;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.SystemInfoRt;
import com.intellij.openapi.util.registry.Registry;
+import com.intellij.platform.eel.EelApi;
import com.intellij.util.EnvironmentUtil;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
@@ -21,6 +23,10 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import static com.intellij.openapi.projectRoots.impl.JavaHomeFinderEel.javaHomeFinderEel;
+import static com.intellij.platform.eel.provider.EelProviderUtil.getEelApiBlocking;
+import static com.intellij.platform.eel.provider.EelProviderUtil.getLocalEel;
+
@ApiStatus.Internal
public abstract class JavaHomeFinder {
public static class SystemInfoProvider {
@@ -54,7 +60,11 @@ public abstract class JavaHomeFinder {
* Tries to find existing Java SDKs on this computer.
* If no JDK found, returns possible directories to start file chooser.
* @return suggested sdk home paths (sorted)
+ *
+ * @deprecated Please use {@link JavaHomeFinder#suggestHomePaths(Project)}. The project can be located on a remote machine,
+ * and the SDK should be local to the project, not to the IDE.
*/
+ @Deprecated
public static @NotNull List suggestHomePaths() {
return suggestHomePaths(false);
}
@@ -65,7 +75,22 @@ public abstract class JavaHomeFinder {
* or that need the embedded JetBrains Runtime.
*/
public static @NotNull List suggestHomePaths(boolean forceEmbeddedJava) {
- JavaHomeFinderBasic javaFinder = getFinder(forceEmbeddedJava);
+ return suggestHomePaths(getLocalEel(), forceEmbeddedJava);
+ }
+
+ /**
+ * Tries to find Java SDKs on the machine where {@code project} is located.
+ * If no JDK found, returns possible directories to start file chooser.
+ *
+ * @return suggested sdk home paths (sorted)
+ */
+ public static @NotNull List<@NotNull String> suggestHomePaths(@Nullable Project project) {
+ return suggestHomePaths(getEelApiBlocking(project), false);
+ }
+
+ @ApiStatus.Internal
+ public static @NotNull List suggestHomePaths(@NotNull EelApi eel, boolean forceEmbeddedJava) {
+ JavaHomeFinderBasic javaFinder = getFinder(eel, forceEmbeddedJava);
if (javaFinder == null) return Collections.emptyList();
ArrayList paths = new ArrayList<>(javaFinder.findExistingJdks());
@@ -77,13 +102,21 @@ public abstract class JavaHomeFinder {
return forceEmbeddedJava || Registry.is("java.detector.enabled", true);
}
- private static JavaHomeFinderBasic getFinder(boolean forceEmbeddedJava) {
+ private static JavaHomeFinderBasic getFinder(@NotNull EelApi eel, boolean forceEmbeddedJava) {
if (!isDetectorEnabled(forceEmbeddedJava)) return null;
- return getFinder().checkEmbeddedJava(forceEmbeddedJava);
+ return getFinder(eel).checkEmbeddedJava(forceEmbeddedJava);
}
- public static @NotNull JavaHomeFinderBasic getFinder() {
+ public static @NotNull JavaHomeFinderBasic getFinder(@Nullable Project project) {
+ return getFinder(getEelApiBlocking(project));
+ }
+
+ private static @NotNull JavaHomeFinderBasic getFinder(@NotNull EelApi eel) {
+ if (Registry.is("java.home.finder.use.eel")) {
+ return javaHomeFinderEel(eel);
+ }
+
SystemInfoProvider systemInfoProvider = new SystemInfoProvider();
if (SystemInfo.isWindows) {
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderBasic.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderBasic.java
index 37e113fbcde2..a72b2b7e909d 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderBasic.java
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderBasic.java
@@ -10,6 +10,7 @@ import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.jdkDownloader.JdkInstaller;
import com.intellij.openapi.projectRoots.impl.jdkDownloader.JdkInstallerStore;
+import com.intellij.openapi.projectRoots.impl.jdkDownloader.OsAbstractionForJdkInstaller;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SystemProperties;
@@ -156,7 +157,7 @@ public class JavaHomeFinderBasic {
Set paths = new HashSet<>();
if (myCheckDefaultInstallDir) {
- paths.add(JdkInstaller.getInstance().defaultInstallDir());
+ paths.add(JdkInstaller.getInstance().defaultInstallDir((OsAbstractionForJdkInstaller)null));
}
if (myCheckUsedInstallDirs) {
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderEel.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderEel.kt
new file mode 100644
index 000000000000..95eaadac2ded
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderEel.kt
@@ -0,0 +1,116 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+@file:JvmName("JavaHomeFinderEel")
+
+package com.intellij.openapi.projectRoots.impl
+
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import com.intellij.openapi.progress.runBlockingMaybeCancellable
+import com.intellij.platform.eel.*
+import com.intellij.platform.eel.fs.*
+import com.intellij.platform.eel.path.EelPath
+import com.intellij.platform.eel.provider.utils.awaitProcessResult
+import com.intellij.util.suspendingLazy
+import kotlinx.coroutines.CoroutineScope
+import java.io.IOException
+import java.nio.file.Path
+
+private class EelSystemInfoProvider(private val eel: EelApi) : JavaHomeFinder.SystemInfoProvider() {
+ @Service
+ private class ScopeService(coroutineScope: CoroutineScope) : CoroutineScope by coroutineScope
+
+ private val environmentVariables = service().suspendingLazy {
+ eel.exec.fetchLoginShellEnvVariables()
+ }
+
+ override fun getEnvironmentVariable(name: String): String? = runBlockingMaybeCancellable {
+ environmentVariables.getValue()[name]
+ }
+
+ override fun getPath(path: String, vararg more: String): Path =
+ eel.mapper.toNioPath(EelPath.Absolute.parse(eel.fs.pathOs, path, *more))
+
+ override fun getUserHome(): Path? = with(eel) {
+ mapper.toNioPath(fs.user.home)
+ }
+
+ override fun getFsRoots(): Collection = runBlockingMaybeCancellable {
+ val paths = when (val fs = eel.fs) {
+ is EelFileSystemPosixApi -> listOf(EelPath.Absolute.build("/"))
+ is EelFileSystemWindowsApi -> fs.getRootDirectories()
+ else -> error(fs)
+ }
+ paths.map(eel.mapper::toNioPath)
+ }
+
+ override fun getPathSeparator(): String? =
+ when (val fs = eel.fs) {
+ is EelFileSystemPosixApi -> ":"
+ is EelFileSystemWindowsApi -> ";"
+ else -> error(fs)
+ }
+
+ private val isCaseSensitive = service().suspendingLazy {
+ val testDir = eel.fs.user.home
+ val type = when (val stat = eel.fs.stat(testDir, EelFileSystemApi.SymlinkPolicy.RESOLVE_AND_FOLLOW)) {
+ is EelResult.Ok -> stat.value.type
+ is EelResult.Error -> error(stat)
+ }
+
+ val sensitivity = when (val type = type) {
+ is EelFileInfo.Type.Directory -> type.sensitivity
+ is EelFileInfo.Type.Other, is EelFileInfo.Type.Regular, is EelPosixFileInfo.Type.Symlink -> error("Not a directory")
+ }
+
+ when (sensitivity) {
+ EelFileInfo.CaseSensitivity.SENSITIVE -> true
+ EelFileInfo.CaseSensitivity.INSENSITIVE -> false
+ EelFileInfo.CaseSensitivity.UNKNOWN -> true
+ }
+ }
+
+ override fun isFileSystemCaseSensitive(): Boolean = runBlockingMaybeCancellable {
+ isCaseSensitive.getValue()
+ }
+}
+
+internal fun javaHomeFinderEel(eel: EelApi): JavaHomeFinderBasic {
+ val systemInfoProvider = EelSystemInfoProvider(eel)
+
+ val parentFinder = when (eel.platform) {
+ is EelPlatform.Windows ->
+ JavaHomeFinderWindows(
+ registeredJdks = true,
+ wslJdks = false,
+ systemInfoProvider = systemInfoProvider,
+ processRunner = { cmd ->
+ runBlockingMaybeCancellable {
+ // TODO Introduce Windows Registry access in EelApi
+ val process = eel.exec.execute(EelExecApi.ExecuteProcessOptions.Builder(cmd.first()).args(cmd.drop(1)).build()).getOrThrow {
+ throw IOException("Failed to read Windows Registry: $it")
+ }
+ val result = process.awaitProcessResult()
+ if (result.exitCode != 0) throw IOException("Failed to read Windows Registry: $result")
+ result.stdout
+ }
+ }
+ )
+
+ is EelPlatform.Darwin -> JavaHomeFinderMac(systemInfoProvider)
+
+ is EelPlatform.Linux -> {
+ val checkPaths = JavaHomeFinder.DEFAULT_JAVA_LINUX_PATHS.toMutableSet()
+ val userHome = eel.fs.user.home
+ checkPaths.add(eel.mapper.toNioPath(userHome.resolve(EelPath.Relative.build(".jdks"))).toString())
+ JavaHomeFinderBasic(systemInfoProvider).checkSpecifiedPaths(*checkPaths.toTypedArray())
+ }
+
+ is EelPlatform.Posix -> JavaHomeFinderBasic(systemInfoProvider)
+ }
+
+ val isLocal = eel is LocalEelApi
+ return parentFinder
+ .checkDefaultInstallDir(isLocal)
+ .checkUsedInstallDirs(isLocal)
+ .checkConfiguredJdks(isLocal)
+}
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderWindows.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderWindows.kt
index 57c53ed2a66e..e622dee123fe 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderWindows.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JavaHomeFinderWindows.kt
@@ -23,7 +23,7 @@ class JavaHomeFinderWindows : JavaHomeFinderBasic {
const val defaultJavaLocation: String = "C:\\Program Files"
@Suppress("SpellCheckingInspection")
- private const val regCommand = """reg query HKLM\SOFTWARE\JavaSoft\JDK /s /v JavaHome"""
+ private val regCommand = listOf("reg", "query", """HKLM\SOFTWARE\JavaSoft\JDK""", "/s", "/v", "JavaHome")
private val javaHomePattern = Regex("""^\s+JavaHome\s+REG_SZ\s+(\S.+\S)\s*$""", setOf(MULTILINE, IGNORE_CASE))
@@ -40,9 +40,17 @@ class JavaHomeFinderWindows : JavaHomeFinderBasic {
}
}
- constructor(registeredJdks: Boolean,
- wslJdks: Boolean,
- systemInfoProvider: JavaHomeFinder.SystemInfoProvider) : super(systemInfoProvider) {
+ private val processRunner: (cmd: List) -> CharSequence
+
+ @JvmOverloads
+ constructor(
+ registeredJdks: Boolean,
+ wslJdks: Boolean,
+ systemInfoProvider: JavaHomeFinder.SystemInfoProvider,
+ processRunner: (cmd: List) -> CharSequence = { cmd -> WindowsRegistryUtil.readRegistry(cmd.joinToString(" ")) },
+ ) : super(systemInfoProvider) {
+ this.processRunner = processRunner
+
if (registeredJdks) {
/** Whether the OS is 64-bit (**important**: it's not the same as [com.intellij.util.system.CpuArch]). */
val os64bit = !systemInfoProvider.getEnvironmentVariable("ProgramFiles(x86)").isNullOrBlank()
@@ -90,11 +98,11 @@ class JavaHomeFinderWindows : JavaHomeFinderBasic {
val cmd =
when (b) {
null -> regCommand
- Bitness.x32 -> "$regCommand /reg:32"
- Bitness.x64 -> "$regCommand /reg:64"
+ Bitness.x32 -> regCommand + "/reg:32"
+ Bitness.x64 -> regCommand + "/reg:64"
}
try {
- val registryLines: CharSequence = WindowsRegistryUtil.readRegistry(cmd)
+ val registryLines: CharSequence = processRunner(cmd)
val registeredPaths = gatherHomePaths(registryLines)
val folders: MutableSet = TreeSet()
for (rp in registeredPaths) {
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JdkFinderImpl.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JdkFinderImpl.java
index c72c4bab714c..2207267c4455 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JdkFinderImpl.java
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/JdkFinderImpl.java
@@ -1,7 +1,9 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.projectRoots.impl;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JdkFinder;
+import com.intellij.platform.eel.provider.EelProviderUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -19,4 +21,9 @@ public final class JdkFinderImpl implements JdkFinder {
public @Nullable String defaultJavaLocation() {
return JavaHomeFinder.defaultJavaLocation();
}
+
+ @Override
+ public @NotNull List<@NotNull String> suggestHomePaths(@Nullable Project project) {
+ return JavaHomeFinder.suggestHomePaths(EelProviderUtil.getEelApiBlocking(project), false);
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkAuto.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkAuto.kt
index 0000fe386752..6b2aa9122253 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkAuto.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkAuto.kt
@@ -6,11 +6,13 @@ import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.components.BaseState
+import com.intellij.openapi.components.Service
import com.intellij.openapi.components.SimplePersistentStateComponent
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicator
+import com.intellij.openapi.progress.runBlockingCancellable
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectBundle
import com.intellij.openapi.projectRoots.*
@@ -26,10 +28,15 @@ import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.JarFileSystem
import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.platform.eel.provider.getEelApi
+import com.intellij.platform.eel.provider.localEel
+import com.intellij.util.SuspendingLazy
import com.intellij.util.lang.JavaVersion
+import com.intellij.util.suspendingLazy
import com.intellij.util.system.CpuArch
import com.intellij.util.text.nullize
import com.intellij.util.xmlb.annotations.XCollection
+import kotlinx.coroutines.CoroutineScope
import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NotNull
import org.jetbrains.jps.model.java.JdkVersionDetector
@@ -99,6 +106,9 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase {
return createResolverImpl(project, indicator)
}
+ @Service
+ private class ServiceScope(val coroutineScope: CoroutineScope)
+
fun createResolverImpl(project: Project?, indicator: ProgressIndicator): UnknownSdkLookup? {
val sdkType = SdkType.getAllTypeList()
.asSequence()
@@ -111,19 +121,27 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase {
}.firstOrNull() ?: return null
return object : UnknownSdkLookup {
+ private val coroutineScope = service().coroutineScope
+
val projectWslDistribution by lazy {
project?.basePath?.let { WslPath.getDistributionByWindowsUncPath(it) }
}
+ val eel = coroutineScope.suspendingLazy {
+ project?.getEelApi() ?: localEel
+ }
+
+ @Deprecated("Remove when EelApi is stabilized")
val projectInWsl by lazy {
project?.basePath?.let { WslPath.isWslUncPath(it) } == true
}
- val lazyDownloadModel: List by lazy {
+ val lazyDownloadModel: SuspendingLazy> = coroutineScope.suspendingLazy {
indicator.pushState()
indicator.text = ProjectBundle.message("progress.text.downloading.jdk.list")
try {
val jdkPredicate = when {
+ Registry.`is`("java.home.finder.use.eel") -> JdkPredicate.forEel(eel.getValue())
projectInWsl -> JdkPredicate.forWSL()
else -> JdkPredicate.default()
}
@@ -196,12 +214,16 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase {
override fun proposeDownload(sdk: UnknownSdk, indicator: ProgressIndicator): UnknownSdkDownloadableSdkFix? = proposeDownload(sdk, indicator, null)
override fun proposeDownload(sdk: UnknownSdk, indicator: ProgressIndicator, lookupReason: @Nls String?): UnknownSdkDownloadableSdkFix? {
+ return runBlockingCancellable { proposeDownload0(sdk, lookupReason) }
+ }
+
+ private suspend fun proposeDownload0(sdk: UnknownSdk, lookupReason: @Nls String?): UnknownSdkDownloadableSdkFix? {
if (sdk.sdkType != sdkType) return null
val req = parseSdkRequirement(sdk) ?: return null
LOG.info("Looking for a possible download for ${sdk.sdkType.presentableName} with name ${sdk.sdkName} ; $req")
- val jdks = lazyDownloadModel
+ val jdks = lazyDownloadModel.getValue()
.asSequence()
.filter { CpuArch.fromString(it.arch) == CpuArch.CURRENT }
.mapNotNull {
@@ -221,10 +243,10 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase {
val jarConfigurator = JarSdkConfigurator(resolveHint(sdk)?.includeJars ?: listOf())
- if (jdkToDownload != null) {
- return singleJdkDownloadFix(jarConfigurator, jdkToDownload.first, lookupReason)
+ return if (jdkToDownload != null) {
+ singleJdkDownloadFix(jarConfigurator, jdkToDownload.first, lookupReason)
} else {
- return multipleJdksDownloadFix(jarConfigurator, matchingJdks, lookupReason)
+ multipleJdksDownloadFix(jarConfigurator, matchingJdks, lookupReason)
}
}
@@ -239,11 +261,11 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase {
override fun getSdkLookupReason(): String? = lookupReason
override fun getDownloadDescription() = jdkToDownload.fullPresentationText + " (${(jdkToDownload.archiveSize / 1024 / 1024).toInt()} MB)"
- override fun createTask(indicator: ProgressIndicator): SdkDownloadTask {
+ override fun createTask(indicator: ProgressIndicator): SdkDownloadTask = runBlockingCancellable {
val jdkInstaller = JdkInstaller.getInstance()
- val homeDir = jdkInstaller.defaultInstallDir(jdkToDownload, projectWslDistribution)
+ val homeDir = jdkInstaller.defaultInstallDir(jdkToDownload, eel.getValue(), projectWslDistribution)
val request = jdkInstaller.prepareJdkInstallation(jdkToDownload, homeDir)
- return JdkDownloaderBase.newDownloadTask(jdkToDownload, request, project)
+ JdkDownloaderBase.newDownloadTask(jdkToDownload, request, project)
}
override fun toString() = "UnknownSdkDownloadableFix{${jdkToDownload.fullPresentationText}, wsl=${projectWslDistribution}}"
@@ -264,11 +286,11 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase {
override fun getSdkLookupReason(): String? = lookupReason ?: ProjectBundle.message("sdk.download.picker.text", ApplicationInfo.getInstance().fullApplicationName)
override fun getDownloadDescription() = item.fullPresentationText + " (${item.archiveSizeInMB} MB)"
- override fun createTask(indicator: ProgressIndicator): SdkDownloadTask {
+ override fun createTask(indicator: ProgressIndicator): SdkDownloadTask = runBlockingCancellable {
val jdkInstaller = JdkInstaller.getInstance()
- val path = homeDir ?: jdkInstaller.defaultInstallDir(item, projectWslDistribution)
+ val path = homeDir ?: jdkInstaller.defaultInstallDir(item, eel.getValue(), projectWslDistribution)
val request = jdkInstaller.prepareJdkInstallation(item, path)
- return JdkDownloaderBase.newDownloadTask(item, request, project)
+ JdkDownloaderBase.newDownloadTask(item, request, project)
}
override fun toString() = "UnknownSdkMultipleDownloadsFix{${items.joinToString(" / ") { it.fullPresentationText }}, wsl=${projectWslDistribution}}"
@@ -286,7 +308,7 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase {
indicator.text = ProjectBundle.message("progress.text.detecting.local.jdks")
val result = mutableListOf()
- SdkDetector.getInstance().detectSdks(sdkType, indicator, object : DetectedSdkListener {
+ SdkDetector.getInstance().detectSdks(project, sdkType, indicator, object : DetectedSdkListener {
override fun onSdkDetected(type: SdkType, version: String, home: String) {
val javaVersion = JavaVersion.tryParse(version) ?: return
val suggestedName = JdkUtil.suggestJdkName(version) ?: return
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloadDialog.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloadDialog.kt
index d6305d4263f6..0cd815a6acd0 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloadDialog.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloadDialog.kt
@@ -12,6 +12,7 @@ import com.intellij.openapi.ui.popup.ListSeparator
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.util.io.FileUtil
+import com.intellij.platform.eel.EelApi
import com.intellij.ui.*
import com.intellij.ui.components.textFieldWithBrowseButton
import com.intellij.ui.dsl.builder.AlignX
@@ -204,14 +205,26 @@ fun buildJdkDownloaderModel(allItems: List, itemFilter: (JdkItem) -> Bo
}
internal class JdkDownloaderMergedModel(
+ @Deprecated("Remove when eelModel is stabilized")
private val mainModel: JdkDownloaderModel,
+
+ @Deprecated("Remove when eelModel is stabilized")
private val wslModel: JdkDownloaderModel?,
+
+ private val eelModel: JdkDownloaderModel?,
+
+ val eel: EelApi?,
val wslDistributions: List,
val projectWSLDistribution: WSLDistribution?
) {
+ val hasEel: Boolean get() = eelModel != null
+
+ @Deprecated("Remove when eelModel is stabilized")
val hasWsl: Boolean get() = wslModel != null
+ @Deprecated("Remove when eelModel is stabilized")
fun selectModel(wsl: Boolean): JdkDownloaderModel = when {
+ eelModel != null -> eelModel
wsl && wslModel != null -> wslModel
else -> mainModel
}
@@ -290,7 +303,7 @@ internal class JdkDownloadDialog(
}
private fun setupContainer(): JComponent {
- if (mergedModel.hasWsl) {
+ if (mergedModel.hasWsl && !mergedModel.hasEel) { // TODO File chooser for Eel
installDirCombo = ComboBox().apply {
isEditable = true
initBrowsableEditor(
@@ -363,7 +376,7 @@ internal class JdkDownloadDialog(
vendorComboBox.selectedItem = it.selectItem
val newVersion = it.item
- val path = JdkInstaller.getInstance().defaultInstallDir(newVersion, mergedModel.projectWSLDistribution).toString()
+ val path = JdkInstaller.getInstance().defaultInstallDir(newVersion, mergedModel.eel, mergedModel.projectWSLDistribution).toString()
val relativePath = FileUtil.getLocationRelativeToUserHome(path)
if (installDirTextField != null) {
installDirTextField!!.text = relativePath
@@ -376,8 +389,11 @@ internal class JdkDownloadDialog(
}
private fun getSuggestedInstallDirs(newVersion: JdkItem): List {
+ if (mergedModel.hasEel) {
+ return listOf(JdkInstaller.getInstance().defaultInstallDir(newVersion, mergedModel.eel, null).toString())
+ }
return (listOf(null) + mergedModel.wslDistributions).mapTo(LinkedHashSet()) {
- JdkInstaller.getInstance().defaultInstallDir(newVersion, it).toString()
+ JdkInstaller.getInstance().defaultInstallDir(newVersion, null, it).toString()
}.map {
FileUtil.getLocationRelativeToUserHome(it)
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloader.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloader.kt
index 6bb1f5072688..e3a38b119346 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloader.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloader.kt
@@ -24,6 +24,8 @@ import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTask
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.registry.Registry
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.provider.getEelApiBlocking
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.Nls
import java.nio.file.Path
@@ -38,10 +40,14 @@ internal val JDK_DOWNLOADER_EXT: DataKey = Dat
internal interface JdkDownloaderDialogHostExtension {
fun allowWsl() : Boolean = true
+ fun allowEel() : Boolean = Registry.`is`("java.home.finder.use.eel")
+
fun createMainPredicate() : JdkPredicate? = null
fun createWslPredicate() : JdkPredicate? = null
+ fun createEelPredicate(eel: EelApi) : JdkPredicate? = null
+
fun shouldIncludeItem(sdkType: SdkTypeId, item: JdkItem) : Boolean = true
}
@@ -137,7 +143,22 @@ class JdkDownloader : SdkDownload, JdkDownloaderBase {
val mainModel = buildModel(extension.createMainPredicate() ?: JdkPredicate.default()) ?: return@computeInBackground null
val wslModel = if (allowWsl && wslDistributions.isNotEmpty()) buildModel(extension.createWslPredicate() ?: JdkPredicate.forWSL()) else null
- JdkDownloaderMergedModel(mainModel, wslModel, wslDistributions, projectWslDistribution)
+
+ val eelPair: Pair? =
+ if (extension.allowEel()) {
+ val eel = project.getEelApiBlocking()
+ buildModel(extension.createEelPredicate(eel) ?: JdkPredicate.forEel(eel))?.let { eel to it}
+ }
+ else null
+
+ JdkDownloaderMergedModel(
+ mainModel = mainModel,
+ wslModel = wslModel,
+ eelModel = eelPair?.second,
+ wslDistributions = wslDistributions,
+ eel = eelPair?.first,
+ projectWSLDistribution = projectWslDistribution,
+ )
}
}
catch (e: Throwable) {
@@ -207,7 +228,17 @@ internal fun selectJdkAndPath(
val projectWslDistribution = if (allowWsl) project?.basePath?.let { WslPath.getDistributionByWindowsUncPath(it) } else null
val mainModel = buildJdkDownloaderModel(items) { extension.shouldIncludeItem(sdkTypeId, it) }
- val mergedModel = JdkDownloaderMergedModel(mainModel, null, wslDistributions, projectWslDistribution)
+
+ val eelModel = null // TODO What should be here?
+
+ val mergedModel = JdkDownloaderMergedModel(
+ mainModel = mainModel,
+ wslModel = null,
+ eelModel = eelModel,
+ eel = null,
+ wslDistributions = wslDistributions,
+ projectWSLDistribution = projectWslDistribution,
+ )
if (project?.isDisposed == true) return null
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstaller.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstaller.kt
index d09153093da6..40bf6b8444e5 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstaller.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstaller.kt
@@ -13,20 +13,32 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicator
+import com.intellij.openapi.progress.runBlockingCancellable
+import com.intellij.openapi.progress.runBlockingMaybeCancellable
import com.intellij.openapi.progress.util.ProgressIndicatorBase
import com.intellij.openapi.progress.util.RelayUiToDelegateIndicator
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectBundle
import com.intellij.openapi.projectRoots.JdkUtil
+import com.intellij.openapi.projectRoots.impl.jdkDownloader.JdkInstallerEel.unpackJdkOnEel
import com.intellij.openapi.projectRoots.impl.jdkDownloader.JdkInstallerWSL.unpackJdkOnWsl
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.registry.Registry
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.EelExecApi
+import com.intellij.platform.eel.EelPlatform
+import com.intellij.platform.eel.getOrThrow
+import com.intellij.platform.eel.path.EelPath
+import com.intellij.platform.eel.provider.getEelApi
+import com.intellij.platform.eel.provider.utils.awaitProcessResult
import com.intellij.util.Urls
import com.intellij.util.io.HttpRequests
import com.intellij.util.io.delete
import com.intellij.util.xmlb.annotations.Tag
import com.intellij.util.xmlb.annotations.XCollection
+import kotlinx.coroutines.TimeoutCancellationException
+import kotlinx.coroutines.withTimeout
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.Nls
import java.nio.file.Files
@@ -41,6 +53,7 @@ import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.isRegularFile
import kotlin.math.absoluteValue
+import kotlin.time.Duration.Companion.milliseconds
@Internal
interface JdkInstallRequest {
@@ -90,21 +103,52 @@ class JdkInstaller : JdkInstallerBase() {
override fun findHistoryRoots(feedItem: JdkItem): List = service().findInstallations(feedItem)
- public override fun wslDistributionFromPath(targetDir: Path): WSLDistributionForJdkInstaller? {
+ public override fun wslDistributionFromPath(targetDir: Path): OsAbstractionForJdkInstaller.Wsl? {
val d = WslPath.getDistributionByWindowsUncPath(targetDir.toString()) ?: return null
return wrap(d)
}
+ public override fun eelFromPath(targetDir: Path): OsAbstractionForJdkInstaller.Eel? =
+ if (Registry.`is`("java.home.finder.use.eel"))
+ EelForJdkInstallerImpl(runBlockingMaybeCancellable {
+ targetDir.getEelApi()
+ })
+ else
+ null
+
private fun wrap(d: WSLDistribution) = WSLDistributionForJdkInstallerImpl(d)
- private class WSLDistributionForJdkInstallerImpl(val d: WSLDistribution) : WSLDistributionForJdkInstaller {
- override fun getWslPath(path: Path): String = d.getWslPath(path) ?: error("Failed to map $path to WSL")
+ private class WSLDistributionForJdkInstallerImpl(override val d: WSLDistribution) : OsAbstractionForJdkInstaller.Wsl {
+ override fun getPath(path: Path): String = d.getWslPath(path) ?: error("Failed to map $path to WSL")
- override fun executeOnWsl(command: List, dir: String, timeout: Int): ProcessOutput {
+ override fun execute(command: List, dir: String, timeout: Int): ProcessOutput {
return d.executeOnWsl(command, WSLCommandLineOptions().setRemoteWorkingDirectory(dir), timeout, null)
}
}
+ private class EelForJdkInstallerImpl(override val eel: EelApi) : OsAbstractionForJdkInstaller.Eel {
+ override fun getPath(path: Path): String =
+ eel.mapper.getOriginalPath(path)?.toString() ?: error("Failed to map $path to WSL")
+
+ override fun execute(command: List, dir: String, timeout: Int): ProcessOutput = runBlockingCancellable {
+ val builder = EelExecApi
+ .ExecuteProcessOptions.Builder(command.first())
+ .args(command.drop(1))
+ .workingDirectory(dir)
+ .build()
+ val process = eel.exec.execute(builder).getOrThrow()
+ try {
+ withTimeout(timeout.milliseconds) {
+ process.awaitProcessResult()
+ }
+ }
+ catch (_: TimeoutCancellationException) {
+ process.terminate() // TODO Originally there was a much more difficult logic of termination.
+ ProcessOutput("", "", -1, true, false)
+ }
+ }
+ }
+
override fun installJdkImpl(request: JdkInstallRequest, indicator: ProgressIndicator?, project: Project?) {
JDK_INSTALL_LISTENER_EP_NAME.forEachExtensionSafe { it.onJdkDownloadStarted(request, project) }
try {
@@ -115,10 +159,24 @@ class JdkInstaller : JdkInstallerBase() {
}
}
- override fun defaultInstallDir(wslDistribution: WSLDistributionForJdkInstaller?): Path {
- if (wslDistribution is WSLDistributionForJdkInstallerImpl) return defaultInstallDir(wslDistribution.d)
+ override fun defaultInstallDir(osAbstraction: OsAbstractionForJdkInstaller?): Path =
+ when (osAbstraction) {
+ is OsAbstractionForJdkInstaller.Eel -> defaultInstallDir(osAbstraction.eel)
+ is OsAbstractionForJdkInstaller.Wsl -> defaultInstallDir(osAbstraction.d)
+ null -> defaultInstallDirForLocalOs()
+ }
- return defaultInstallDir()
+ private fun defaultInstallDir(eel: EelApi): Path {
+ val userHome = eel.fs.user.home
+
+ val relativePath = EelPath.Relative.parse(
+ when (eel.platform) {
+ is EelPlatform.Windows, is EelPlatform.Linux -> ".jdks"
+ is EelPlatform.Darwin -> "Library/Java/JavaVirtualMachines"
+ })
+
+ val jdks = userHome.resolve(relativePath)
+ return eel.mapper.toNioPath(jdks)
}
private fun defaultInstallDir(wslDistribution: WSLDistribution?) : Path {
@@ -128,10 +186,10 @@ class JdkInstaller : JdkInstallerBase() {
}
}
- return defaultInstallDir()
+ return defaultInstallDirForLocalOs()
}
- override fun defaultInstallDir(): Path {
+ private fun defaultInstallDirForLocalOs(): Path {
val explicitHome = System.getProperty("jdk.downloader.home")
if (explicitHome != null) {
return Paths.get(explicitHome)
@@ -147,15 +205,26 @@ class JdkInstaller : JdkInstallerBase() {
}
}
- fun defaultInstallDir(newVersion: JdkItem, wslDistribution: WSLDistribution? = null) : Path {
- return defaultInstallDir(defaultInstallDir(wslDistribution), newVersion)
+ fun defaultInstallDir(newVersion: JdkItem, eel: EelApi?, wslDistribution: WSLDistribution? = null): Path {
+ val installDir =
+ if (eel != null) defaultInstallDir(eel)
+ else defaultInstallDir(wslDistribution)
+ return defaultInstallDir(installDir, newVersion)
}
}
@Internal
-interface WSLDistributionForJdkInstaller {
- fun getWslPath(path: Path): String
- fun executeOnWsl(command: List, dir: String, timeout: Int): ProcessOutput
+sealed interface OsAbstractionForJdkInstaller {
+ fun getPath(path: Path): String
+ fun execute(command: List, dir: String, timeout: Int): ProcessOutput
+
+ interface Eel : OsAbstractionForJdkInstaller {
+ val eel: EelApi
+ }
+
+ interface Wsl : OsAbstractionForJdkInstaller {
+ val d: WSLDistribution
+ }
}
@Internal
@@ -163,12 +232,11 @@ abstract class JdkInstallerBase {
@Suppress("PropertyName", "SSBasedInspection")
protected val LOG: Logger = Logger.getInstance(javaClass)
- abstract fun defaultInstallDir() : Path
- open fun defaultInstallDir(wslDistribution: WSLDistributionForJdkInstaller?) : Path = defaultInstallDir()
+ abstract fun defaultInstallDir(osAbstractionForJdkInstaller: OsAbstractionForJdkInstaller?): Path
- fun defaultInstallDir(newVersion: JdkItem) : Path = defaultInstallDir(defaultInstallDir(), newVersion)
+ fun defaultInstallDir(newVersion: JdkItem): Path = defaultInstallDir(defaultInstallDir(null), newVersion)
- protected fun defaultInstallDir(installDir: Path, newVersion: JdkItem) : Path {
+ protected fun defaultInstallDir(installDir: Path, newVersion: JdkItem): Path {
val targetDir = installDir.resolve(newVersion.installFolderName)
var count = 1
var uniqueDir = targetDir
@@ -240,15 +308,23 @@ abstract class JdkInstallerBase {
error("URL must use https:// protocol, but was: $url")
}
- val wslDistribution = wslDistributionFromPath(targetDir)
- if (wslDistribution != null && item.os != "linux") {
- JdkDownloaderLogger.logFailed(JdkDownloaderLogger.DownloadFailure.WSLIssue)
- logFailed = true
- error("Cannot install non-linux JDK into WSL environment to $targetDir from $item")
+ val eel = eelFromPath(targetDir)?.eel
+ val wslDistribution: OsAbstractionForJdkInstaller.Wsl?
+ if (eel != null) {
+ wslDistribution = null
+ }
+ else {
+ wslDistribution = wslDistributionFromPath(targetDir)
+ if (wslDistribution != null && item.os != "linux") {
+ JdkDownloaderLogger.logFailed(JdkDownloaderLogger.DownloadFailure.WSLIssue)
+ logFailed = true
+ error("Cannot install non-linux JDK into WSL environment to $targetDir from $item")
+ }
}
indicator?.text2 = ProjectBundle.message("progress.text2.downloading.jdk")
- val downloadFile = Paths.get(PathManager.getTempPath(), FileUtil.sanitizeFileName("jdk-${System.nanoTime()}-${item.archiveFileName}"))
+ // TODO Sanitize `archiveFileName` in a way that it doesn't replace `.` with `_`. `FileUtil.sanitizeFileName` can't be applied here.
+ val downloadFile = Paths.get(PathManager.getTempPath(), "jdk-${System.nanoTime()}-${item.archiveFileName}")
try {
try {
HttpRequests.request(item.url)
@@ -290,7 +366,11 @@ abstract class JdkInstallerBase {
indicator?.text2 = ProjectBundle.message("progress.text2.unpacking.jdk")
try {
- if (wslDistribution != null) {
+ if (eel != null) {
+ val targetDirEel = eel.mapper.getOriginalPath(targetDir) ?: TODO("Failed to map $targetDir to $eel")
+ unpackJdkOnEel(eel, downloadFile, targetDirEel, item.packageRootPrefix)
+ }
+ else if (wslDistribution != null) {
unpackJdkOnWsl(wslDistribution, item.packageType, downloadFile, targetDir, item.packageRootPrefix)
}
else {
@@ -428,7 +508,7 @@ abstract class JdkInstallerBase {
}
}
- private fun findAlreadyInstalledJdk(feedItem: JdkItem, distribution: WSLDistributionForJdkInstaller?) : JdkInstallRequest? {
+ private fun findAlreadyInstalledJdk(feedItem: JdkItem, distribution: OsAbstractionForJdkInstaller?) : JdkInstallRequest? {
try {
val localRoots = run {
val defaultInstallDir = defaultInstallDir(distribution)
@@ -461,7 +541,8 @@ abstract class JdkInstallerBase {
}
protected open fun findHistoryRoots(feedItem: JdkItem): List = listOf()
- protected open fun wslDistributionFromPath(targetDir: Path) : WSLDistributionForJdkInstaller? = null
+ protected open fun wslDistributionFromPath(targetDir: Path) : OsAbstractionForJdkInstaller.Wsl? = null
+ protected open fun eelFromPath(targetDir: Path): OsAbstractionForJdkInstaller.Eel? = null
}
private data class PendingJdkRequest(
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstallerEel.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstallerEel.kt
new file mode 100644
index 000000000000..7027f0fff9a2
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstallerEel.kt
@@ -0,0 +1,94 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.openapi.projectRoots.impl.jdkDownloader
+
+import com.intellij.openapi.diagnostic.thisLogger
+import com.intellij.openapi.progress.runBlockingMaybeCancellable
+import com.intellij.openapi.util.io.NioFiles
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.fs.EelFileSystemApi
+import com.intellij.platform.eel.getOrThrow
+import com.intellij.platform.eel.path.EelPath
+import com.intellij.platform.eel.toNioPath
+import org.jetbrains.annotations.ApiStatus.Internal
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardCopyOption
+import kotlin.io.path.name
+
+@Internal
+object JdkInstallerEel {
+ fun unpackJdkOnEel(
+ eel: EelApi,
+ downloadFile: Path,
+ targetDirEel: EelPath.Absolute,
+ packageRootPrefixRaw: String,
+ ): Unit = runBlockingMaybeCancellable {
+ var downloadFileEelCopy: EelPath.Absolute? = eel.mapper.getOriginalPath(downloadFile)
+
+ val tempDirectory: EelPath.Absolute? =
+ if (downloadFileEelCopy == null) {
+ // TODO Eel downloading API
+ val archiveName = EelPath.Relative.parse(downloadFile.name)
+
+ downloadFileEelCopy = eel.fs
+ .createTemporaryDirectory(EelFileSystemApi.CreateTemporaryDirectoryOptions.Builder().prefix("download-jdk-").build()).getOrThrow()
+ .resolve(archiveName)
+
+ Files.copy(downloadFile, downloadFileEelCopy.toNioPath(eel), StandardCopyOption.REPLACE_EXISTING)
+
+ downloadFileEelCopy.parent
+ }
+ else null
+ try {
+ val unpackDir = targetDirEel.parent!!
+ .resolve(EelPath.Relative.parse(".${targetDirEel.fileName}-downloading-${System.currentTimeMillis()}"))
+ try {
+ eel.archive.extract(downloadFileEelCopy, unpackDir)
+ moveUnpackedJdkPrefixOnEel(
+ eel = eel,
+ unpackDir = unpackDir,
+ targetDir = targetDirEel,
+ packageRootPrefixRaw = packageRootPrefixRaw,
+ )
+ }
+ finally {
+ try {
+ NioFiles.deleteRecursively(unpackDir.toNioPath(eel))
+ }
+ catch (_: FileSystemException) {
+ // Ignored.
+ }
+ }
+ }
+ finally {
+ tempDirectory?.let(eel.mapper::toNioPath)?.let { absolute ->
+ NioFiles.deleteRecursively(absolute)
+ }
+ }
+ }
+
+ private suspend fun moveUnpackedJdkPrefixOnEel(
+ eel: EelApi,
+ unpackDir: EelPath.Absolute,
+ targetDir: EelPath.Absolute,
+ packageRootPrefixRaw: String,
+ ) {
+ val packageRootPrefix = packageRootPrefixRaw.removePrefix("./").trim('/')
+ val packageRootResolved =
+ if (packageRootPrefix.isBlank())
+ unpackDir
+ else
+ unpackDir.resolve(EelPath.Relative.parse(packageRootPrefixRaw)).normalize()
+
+
+ if (!packageRootResolved.startsWith(unpackDir)) {
+ error("Failed to move JDK contents from $unpackDir to $packageRootResolved. Invalid metadata is detected")
+ }
+
+ if (!Files.isDirectory(packageRootResolved.toNioPath(eel))) {
+ thisLogger().info("Could not unpack JDK in $packageRootResolved. File system entry is not a directory. ")
+ return
+ }
+ eel.fs.move(packageRootResolved, targetDir, EelFileSystemApi.ReplaceExistingDuringMove.REPLACE_EVERYTHING, true)
+ }
+}
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstallerWSL.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstallerWSL.kt
index 2c2cc89c92c3..6e8228482325 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstallerWSL.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkInstallerWSL.kt
@@ -11,7 +11,7 @@ private val LOG = logger()
@Internal
object JdkInstallerWSL {
- fun unpackJdkOnWsl(wslDistribution: WSLDistributionForJdkInstaller,
+ fun unpackJdkOnWsl(wslDistribution: OsAbstractionForJdkInstaller.Wsl,
packageType: JdkPackageType,
downloadFile: Path,
targetDir: Path,
@@ -31,19 +31,19 @@ object JdkInstallerWSL {
}
}
- private fun unpackJdkArchiveOnWsl(wslDistribution: WSLDistributionForJdkInstaller,
+ private fun unpackJdkArchiveOnWsl(osAbstraction: OsAbstractionForJdkInstaller,
packageType: JdkPackageType,
downloadFile: Path,
targetDir: Path) {
- val downloadFileWslPath = wslDistribution.getWslPath(downloadFile)
- val targetWslPath = wslDistribution.getWslPath(targetDir)
+ val downloadFileWslPath = osAbstraction.getPath(downloadFile)
+ val targetWslPath = osAbstraction.getPath(targetDir)
FileUtil.createDirectory(targetDir.toFile())
val command = when (packageType) {
JdkPackageType.ZIP -> listOf("unzip", downloadFileWslPath)
JdkPackageType.TAR_GZ -> listOf("tar", "xzf", downloadFileWslPath)
}
- val processOutput = wslDistribution.executeOnWsl(command, targetWslPath, 300_000)
+ val processOutput = osAbstraction.execute(command, targetWslPath, 300_000)
if (processOutput.exitCode != 0) {
val message = "Failed to unpack $downloadFile to $targetDir"
LOG.warn(message + ": " + processOutput.stderrLines.takeLast(10).joinToString("") { "\n $it" })
@@ -52,7 +52,7 @@ object JdkInstallerWSL {
}
private fun moveUnpackedJdkPrefixOnWsl(
- wslDistribution: WSLDistributionForJdkInstaller,
+ osAbstraction: OsAbstractionForJdkInstaller,
unpackDir: Path,
targetDir: Path,
packageRootPrefixRaw: String,
@@ -68,13 +68,13 @@ object JdkInstallerWSL {
error("Invalid package. Directory is expected under '$packageRootPrefixRaw' path on the JDK package")
}
- val wslTarget = wslDistribution.getWslPath(targetDir)
- val wslUnpack = wslDistribution.getWslPath(unpackDir)
- val wslSource = wslDistribution.getWslPath(packageRootDir)
+ val wslTarget = osAbstraction.getPath(targetDir)
+ val wslUnpack = osAbstraction.getPath(unpackDir)
+ val wslSource = osAbstraction.getPath(packageRootDir)
FileUtil.delete(targetDir)
val command = listOf("mv", wslSource, wslTarget)
- val processOutput = wslDistribution.executeOnWsl(command, wslUnpack, 300_000)
+ val processOutput = osAbstraction.execute(command, wslUnpack, 300_000)
if (processOutput.exitCode != 0) {
val message = "Failed to strip package root prefix ${packageRootPrefix}"
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkList.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkList.kt
index febe34937ab2..816a80cf1610 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkList.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkList.kt
@@ -12,11 +12,14 @@ import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
+import com.intellij.openapi.projectRoots.impl.jdkDownloader.JdkPackageType.entries
import com.intellij.openapi.util.BuildNumber
import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.util.text.StringUtil
+import com.intellij.platform.eel.EelApi
+import com.intellij.platform.eel.EelPlatform
import com.intellij.util.io.Decompressor
import com.intellij.util.io.HttpRequests
import com.intellij.util.io.write
@@ -243,6 +246,12 @@ data class JdkPredicate(
fun default(): JdkPredicate = createInstance(forWsl = false)
fun forWSL(buildNumber: BuildNumber? = ApplicationInfoImpl.getShadowInstance().build): JdkPredicate = createInstance(forWsl = true, buildNumber)
+ fun forEel(
+ eel: EelApi,
+ buildNumber: BuildNumber? = ApplicationInfoImpl.getShadowInstance().build,
+ ): JdkPredicate =
+ createInstance(eel, buildNumber)
+
/**
* Selects only JDKs that are for the same OS and CPU arch as the current Java process.
*/
@@ -263,6 +272,18 @@ data class JdkPredicate(
return JdkPredicate(buildNumber, platforms.toSet())
}
+ private fun createInstance(eel: EelApi, buildNumber: BuildNumber?): JdkPredicate {
+ val platform = when (eel.platform) {
+ EelPlatform.Arm64Darwin -> setOf(JdkPlatform("macOS", "x86_64"), JdkPlatform("macOS", "aarch64"))
+ EelPlatform.X8664Darwin -> setOf(JdkPlatform("macOS", "x86_64"))
+ EelPlatform.Aarch64Linux -> setOf(JdkPlatform("linux", "aarch64"))
+ EelPlatform.X8664Linux -> setOf(JdkPlatform("linux", "x86_64"))
+ EelPlatform.X64Windows -> setOf(JdkPlatform("windows", "x86_64"))
+ // TODO Windows aarch64
+ }
+ return JdkPredicate(buildNumber, platform)
+ }
+
val currentOS: String = when {
SystemInfo.isWindows -> "windows"
SystemInfo.isMac -> "macOS"
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserCustom.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserCustom.kt
index f38ee2c0aa59..2a90cc50b055 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserCustom.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserCustom.kt
@@ -48,6 +48,7 @@ internal object RuntimeChooserCustom {
private val jdkDownloaderExtension = object : JdkDownloaderDialogHostExtension {
override fun allowWsl(): Boolean = false
+ override fun allowEel(): Boolean = false
override fun shouldIncludeItem(sdkType: SdkTypeId, item: JdkItem): Boolean {
return sdkType == this@RuntimeChooserCustom.sdkType && isSupportedSdkItem(item)
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserDownloader.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserDownloader.kt
index 5ca9bb3737dd..8d6b8d079f94 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserDownloader.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserDownloader.kt
@@ -3,7 +3,6 @@ package com.intellij.openapi.projectRoots.impl.jdkDownloader
import com.intellij.lang.LangBundle
import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.progress.ProgressIndicator
@@ -16,7 +15,7 @@ import java.nio.file.Paths
internal class RuntimeChooserDownloader {
fun downloadAndUse(indicator: ProgressIndicator, jdk: JdkItem, targetDir: Path): Path? {
try {
- val installer = service()
+ val installer = RuntimeChooserJbrInstaller
val request = installer.prepareJdkInstallation(jdk, targetDir)
installer.installJdk(request, indicator, null)
return request.javaHome
@@ -32,9 +31,9 @@ internal class RuntimeChooserDownloader {
}
}
-@Service(Service.Level.APP)
-internal class RuntimeChooserJbrInstaller : JdkInstallerBase() {
- override fun defaultInstallDir(): Path {
+internal object RuntimeChooserJbrInstaller : JdkInstallerBase() {
+ override fun defaultInstallDir(osAbstractionForJdkInstaller: OsAbstractionForJdkInstaller?): Path {
+ // TODO Use osAbstractionForJdkInstaller
val explicitHome = System.getProperty("jbr.downloader.home")
if (explicitHome != null) {
return Paths.get(explicitHome)
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserJre.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserJre.kt
index bc069cc9763d..c5edf5468c10 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserJre.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserJre.kt
@@ -35,6 +35,7 @@ internal object RuntimeChooserJreValidator {
get() = 11
fun isSupportedSdkItem(item: JdkItem): Boolean {
+ // TODO Introduce EelApi here.
//we do only support mac bundle layout
if (SystemInfo.isMac && !item.packageToBinJavaPrefix.endsWith("Contents/Home")) {
return false
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserModel.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserModel.kt
index e16452202f9f..76e46eb5b142 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserModel.kt
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/jdkDownloader/RuntimeChooserModel.kt
@@ -2,7 +2,6 @@
package com.intellij.openapi.projectRoots.impl.jdkDownloader
import com.intellij.openapi.Disposable
-import com.intellij.openapi.components.service
import com.intellij.openapi.observable.properties.GraphProperty
import com.intellij.openapi.observable.properties.PropertyGraph
import com.intellij.openapi.util.io.FileUtil
@@ -49,7 +48,7 @@ internal class RuntimeChooserModel {
file = Paths.get(path + "-" + (it + 1))
}
}
- return service().defaultInstallDir(item)
+ return RuntimeChooserJbrInstaller.defaultInstallDir(item)
}
private fun updateMainCombobox(newSelection: RuntimeChooserItem? = null) {
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkDetector.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkDetector.java
index 8ee75567570d..57b858485ed0 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkDetector.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkDetector.java
@@ -15,6 +15,7 @@ import com.intellij.openapi.projectRoots.SdkType;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.concurrency.ThreadingAssertions;
+import com.intellij.util.concurrency.annotations.RequiresBackgroundThread;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -91,7 +92,7 @@ public class SdkDetector {
*/
BackgroundTaskUtil.executeOnPooledThread(lifetime, () -> {
var progressIndicator = ProgressManager.getInstance().getProgressIndicator();
- detectAllSdks(progressIndicator, myMulticaster);
+ detectAllSdks(project, progressIndicator, myMulticaster);
});
}
@@ -140,16 +141,33 @@ public class SdkDetector {
/**
* Run Sdk detection assuming called in a background thread
+ *
+ * @deprecated Please use {@link SdkDetector#detectSdks(Project, SdkType, ProgressIndicator, DetectedSdkListener)}
*/
+ @Deprecated
public void detectSdks(
@NotNull SdkType type,
@NotNull ProgressIndicator indicator,
@NotNull DetectedSdkListener callback
+ ) {
+ detectSdks(null, type, indicator, callback);
+ }
+
+ /**
+ * Run Sdk detection on the machine where {@code project} is located
+ * This function assumes that it is called in background thread
+ */
+ @RequiresBackgroundThread
+ public void detectSdks(
+ @Nullable Project project,
+ @NotNull SdkType type,
+ @NotNull ProgressIndicator indicator,
+ @NotNull DetectedSdkListener callback
) {
try {
callback.onSearchStarted();
if (isDetectorEnabled()) {
- detect(type, indicator, callback);
+ detect(project, type, indicator, callback);
}
}
finally {
@@ -157,7 +175,7 @@ public class SdkDetector {
}
}
- private static void detectAllSdks(@NotNull ProgressIndicator indicator, @NotNull DetectedSdkListener callback) {
+ private static void detectAllSdks(@NotNull Project project, @NotNull ProgressIndicator indicator, @NotNull DetectedSdkListener callback) {
try {
callback.onSearchStarted();
indicator.setIndeterminate(false);
@@ -166,7 +184,7 @@ public class SdkDetector {
indicator.setFraction((float)i / types.size());
indicator.checkCanceled();
if (isDetectorEnabled()) {
- detect(types.get(i), indicator, callback);
+ detect(project, types.get(i), indicator, callback);
}
}
}
@@ -175,11 +193,12 @@ public class SdkDetector {
}
}
- private static void detect(@NotNull SdkType type,
+ private static void detect(@Nullable Project project,
+ @NotNull SdkType type,
@NotNull ProgressIndicator indicator,
@NotNull DetectedSdkListener callback) {
try {
- Collection suggestedPaths = type.suggestHomePaths();
+ Collection suggestedPaths = type.suggestHomePaths(project);
for (String path : suggestedPaths) {
indicator.checkCanceled();
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java
index b3da869be64b..fb4186af717a 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java
@@ -2,8 +2,10 @@
package com.intellij.openapi.roots.ui.configuration.projectRoot;
import com.intellij.execution.wsl.WslPath;
+import com.intellij.ide.DataManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -21,21 +23,28 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.NlsContexts.ListItem;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.platform.eel.provider.EelApiKey;
+import com.intellij.platform.eel.provider.LocalEelKey;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Consumer;
import com.intellij.util.EventDispatcher;
import com.intellij.util.concurrency.annotations.RequiresEdt;
import one.util.streamex.StreamEx;
+import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import static com.intellij.openapi.util.NlsActions.ActionText;
+import static com.intellij.platform.eel.provider.EelProviderUtil.getEelApiKey;
/**
* @author anna
@@ -80,10 +89,20 @@ public class ProjectSdksModel implements SdkModel {
}
public void syncSdks() {
+ syncSdks(LocalEelKey.INSTANCE);
+ }
+
+ /**
+ * @param eel can be null only if the corresponding feature flag is disabled.
+ */
+ @ApiStatus.Internal
+ public void syncSdks(@Nullable EelApiKey eelApiKey) {
final Sdk[] projectSdks = ProjectJdkTable.getInstance().getAllJdks();
for (Sdk sdk : projectSdks) {
if (myProjectSdks.containsKey(sdk) || myProjectSdks.containsValue(sdk)) continue;
+ if (eelApiKey != null && !sdkMatchesEel(eelApiKey, sdk)) continue;
+
Sdk editableCopy;
try {
editableCopy = sdk.clone();
@@ -99,12 +118,47 @@ public class ProjectSdksModel implements SdkModel {
}
}
+ @ApiStatus.Internal
+ public static boolean sdkMatchesEel(@NotNull EelApiKey eelApiKey, Sdk sdk) {
+ String sdkHomePath = sdk.getHomePath();
+ return sdkMatchesEel(eelApiKey, sdkHomePath);
+ }
+
+ @ApiStatus.Internal
+ public static boolean sdkMatchesEel(@NotNull EelApiKey eelApiKey, String sdkHomePath) {
+ if (sdkHomePath != null) {
+ try {
+ Path path = Path.of(sdkHomePath);
+ if (getEelApiKey(path).equals(eelApiKey)) {
+ return true;
+ }
+ }
+ catch (InvalidPathException ignored) {
+ // Ignored.
+ }
+ }
+ return false;
+ }
+
public void reset(@Nullable Project project) {
+ EelApiKey eelApiKey;
+ if (!Registry.is("java.home.finder.use.eel")) {
+ eelApiKey = null;
+ }
+ else if (project != null) {
+ eelApiKey = getEelApiKey(project);
+ }
+ else {
+ eelApiKey = LocalEelKey.INSTANCE;
+ }
+
myProjectSdks.clear();
ProjectJdkTable jdkTable = ProjectJdkTable.getInstance();
jdkTable.preconfigure();
final Sdk[] projectSdks = jdkTable.getAllJdks();
for (Sdk sdk : projectSdks) {
+ if (eelApiKey != null && !sdkMatchesEel(eelApiKey, sdk)) continue;
+
try {
Sdk editable = sdk.clone();
myProjectSdks.put(sdk, editable);
@@ -370,7 +424,8 @@ public class ProjectSdksModel implements SdkModel {
public void actionPerformed(@Nullable Sdk selectedSdk,
@NotNull JComponent parent,
@NotNull java.util.function.Consumer super Sdk> callback) {
- doDownload(downloadExtension, parent, selectedSdk, type, callback);
+ Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parent));
+ doDownload(project, downloadExtension, parent, selectedSdk, type, callback);
}
};
@@ -421,7 +476,8 @@ public class ProjectSdksModel implements SdkModel {
doAdd(parent, null, type, callback);
}
- public void doDownload(@NotNull SdkDownload downloadExtension,
+ private void doDownload(@Nullable Project project,
+ @NotNull SdkDownload downloadExtension,
@NotNull JComponent parent,
@Nullable Sdk selectedSdk,
@NotNull SdkType type,
@@ -429,7 +485,7 @@ public class ProjectSdksModel implements SdkModel {
LOG.assertTrue(downloadExtension.supportsDownload(type));
myModified = true;
- downloadExtension.showDownloadUI(type, this, parent, null, selectedSdk, null, sdk -> setupInstallableSdk(type, sdk, callback));
+ downloadExtension.showDownloadUI(type, this, parent, project, selectedSdk, null, sdk -> setupInstallableSdk(type, sdk, callback));
}
public void doAdd(@NotNull JComponent parent, final @Nullable Sdk selectedSdk, final @NotNull SdkType type, final @NotNull Consumer super Sdk> callback) {
diff --git a/platform/lang-impl/testSources/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloaderTest.kt b/platform/lang-impl/testSources/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloaderTest.kt
index 066375bf44dd..3a0828eb78c6 100644
--- a/platform/lang-impl/testSources/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloaderTest.kt
+++ b/platform/lang-impl/testSources/com/intellij/openapi/projectRoots/impl/jdkDownloader/JdkDownloaderTest.kt
@@ -5,6 +5,7 @@ package com.intellij.openapi.projectRoots.impl.jdkDownloader
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.CapturingProcessHandler
import com.intellij.execution.process.ProcessOutput
+import com.intellij.execution.wsl.WSLDistribution
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.extensions.ExtensionPointName
@@ -20,7 +21,6 @@ import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import java.io.File
import java.nio.file.Path
import kotlin.concurrent.thread
@@ -79,19 +79,21 @@ class JdkDownloaderTest : BareTestFixtureTestCase() {
size = 604,
sha256 = "1cf15536c1525f413190fd53243f343511a17e6ce7439ccee4dc86f0d34f9e81")
- private val mockWSL = object: WSLDistributionForJdkInstaller {
- override fun getWslPath(path: Path): String = path.toString()
+ private val mockWSL = object: OsAbstractionForJdkInstaller.Wsl {
+ override val d: WSLDistribution
+ get() = TODO("Not yet implemented")
- override fun executeOnWsl(command: List, dir: String, timeout: Int): ProcessOutput {
- val cmd = GeneralCommandLine(command)
- cmd.workDirectory = File(dir)
- return CapturingProcessHandler(cmd).runProcess(timeout)
+ override fun getPath(path: Path): String = path.toString()
+
+ override fun execute(command: List, dir: String, timeout: Int): ProcessOutput {
+ val processHandler = CapturingProcessHandler(GeneralCommandLine(command).withWorkingDirectory(Path.of(dir)));
+ return processHandler.runProcess(timeout)
}
}
private val mockWSLInstaller = object: JdkInstallerBase() {
override fun wslDistributionFromPath(targetDir: Path) = mockWSL
- override fun defaultInstallDir(): Path = error("Must not call")
+ override fun defaultInstallDir(osAbstractionForJdkInstaller: OsAbstractionForJdkInstaller?): Path = error("Must not call")
}
@Test fun `test reuse pending JDKs`() {
diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties
index c745a7122165..468d331d86bd 100644
--- a/platform/util/resources/misc/registry.properties
+++ b/platform/util/resources/misc/registry.properties
@@ -2555,5 +2555,8 @@ i18n.locale.description=changes locale of the IDE
properties.file.encoding.legacy.support=false
properties.file.encoding.legacy.support.description=Switch the encoding for properties files to legacy ISO 8859-1 (used up to Java 8). Starting from Java 9, the default encoding is UTF-8.
+java.home.finder.use.eel=true
+java.home.finder.use.eel.description=Use new API for OS abstraction in Project SDKs
+
# please leave this note as last line
# TODO please use EP com.intellij.registryKey for plugin/product specific keys
diff --git a/plugins/maven/intellij.maven.iml b/plugins/maven/intellij.maven.iml
index ebe5fda33536..585620f4c2dd 100644
--- a/plugins/maven/intellij.maven.iml
+++ b/plugins/maven/intellij.maven.iml
@@ -109,6 +109,8 @@
+
+
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenWslUtil.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenWslUtil.kt
index 6af145a565e2..8a2ec2fab55c 100644
--- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenWslUtil.kt
+++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenWslUtil.kt
@@ -10,6 +10,7 @@ import com.intellij.notification.NotificationListener
import com.intellij.notification.NotificationType
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.WriteAction
+import com.intellij.openapi.application.writeAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.externalSystem.service.execution.InvalidSdkException
@@ -17,6 +18,7 @@ import com.intellij.openapi.options.ShowSettingsUtil
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
+import com.intellij.openapi.progress.coroutineToIndicator
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.*
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
@@ -27,9 +29,15 @@ import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable
import com.intellij.openapi.util.io.FileUtil
+import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.util.text.StringUtil
+import com.intellij.platform.eel.provider.getEelApi
+import com.intellij.platform.ide.progress.withBackgroundProgress
+import com.intellij.platform.util.progress.withProgressText
import com.intellij.ui.navigation.Place
import com.intellij.util.text.VersionComparatorUtil
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import org.jetbrains.idea.maven.config.MavenConfig
import org.jetbrains.idea.maven.config.MavenConfigSettings
import org.jetbrains.idea.maven.execution.MavenRunnerSettings
@@ -358,6 +366,10 @@ object MavenWslUtil : MavenUtil() {
sdk: Sdk,
notification: Notification,
listener: NotificationListener) {
+ if (Registry.`is`("java.home.finder.use.eel")) {
+ return findOrDownloadNewJdkOverEel(project, notification, listener)
+ }
+
val jdkTask = object : Task.Backgroundable(null, MavenProjectBundle.message("wsl.jdk.searching"), false) {
override fun run(indicator: ProgressIndicator) {
val sdkPath = service().suggestHomePaths().filter {
@@ -389,7 +401,7 @@ object MavenWslUtil : MavenUtil() {
}
else {
this.title = MavenProjectBundle.message("wsl.jdk.downloading")
- val homeDir = installer.defaultInstallDir(model[0], projectWslDistr)
+ val homeDir = installer.defaultInstallDir(model[0], null, projectWslDistr)
val request = installer.prepareJdkInstallation(model[0], homeDir)
installer.installJdk(request, indicator, project)
notification.hideBalloon()
@@ -398,6 +410,54 @@ object MavenWslUtil : MavenUtil() {
}
ProgressManager.getInstance().run(jdkTask)
}
+
+ private fun findOrDownloadNewJdkOverEel(
+ project: Project,
+ notification: Notification,
+ listener: NotificationListener,
+ ) {
+ MavenCoroutineScopeProvider.getCoroutineScope(project).launch(Dispatchers.IO) {
+ withBackgroundProgress(project, MavenProjectBundle.message("wsl.jdk.searching"), cancellable = false) {
+ val eel = project.getEelApi()
+ val sdkPath = service().suggestHomePaths(project).firstOrNull()
+ if (sdkPath != null) {
+ writeAction {
+ val jdkName = SdkConfigurationUtil.createUniqueSdkName(JavaSdk.getInstance(), sdkPath,
+ ProjectJdkTable.getInstance().allJdks.toList())
+ val newJdk = JavaSdk.getInstance().createJdk(jdkName, sdkPath)
+ ProjectJdkTable.getInstance().addJdk(newJdk)
+ ProjectRootManagerEx.getInstance(project).projectSdk = newJdk
+ notification.hideBalloon()
+ }
+ return@withBackgroundProgress
+ }
+ val installer = JdkInstaller.getInstance()
+ val jdkPredicate = JdkPredicate.forEel(eel)
+ val model = coroutineToIndicator {
+ JdkListDownloader.getInstance().downloadModelForJdkInstaller(ProgressManager.getGlobalProgressIndicator(), jdkPredicate)
+ }
+ if (model.isEmpty()) {
+ Notification(
+ MAVEN_NOTIFICATION_GROUP,
+ MavenProjectBundle.message("maven.wsl.jdk.fix.failed"),
+ MavenProjectBundle.message("maven.wsl.jdk.fix.failed.descr"),
+ NotificationType.ERROR
+ ).setListener(listener).notify(project)
+
+ }
+ else {
+ withProgressText(MavenProjectBundle.message("wsl.jdk.downloading")) {
+ val homeDir = installer.defaultInstallDir(model[0], eel, null)
+ val request = installer.prepareJdkInstallation(model[0], homeDir)
+ coroutineToIndicator {
+ installer.installJdk(request, ProgressManager.getGlobalProgressIndicator(), project)
+ }
+ notification.hideBalloon()
+ }
+ }
+ }
+ }
+ }
}