mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[eel] IJPL-163027: Move Project Structure -> SDKs to EelApi
GitOrigin-RevId: 20fe00115b3693c50c1485a33635c58bdb83ad73
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6b518ff68c
commit
0f8de35eb7
@@ -34,5 +34,7 @@
|
||||
<orderEntry type="module" module-name="intellij.xml.dom" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
|
||||
<orderEntry type="module" module-name="intellij.platform.backend.observation" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel.provider" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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<Sdk> {
|
||||
val eelApiKey = project.getEelApiKey()
|
||||
return Predicate { sdk ->
|
||||
ProjectSdksModel.sdkMatchesEel(eelApiKey, sdk)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun filterSdkSuggestionByEel(project: Project): Predicate<SdkListItem.SuggestedItem> {
|
||||
val eelApiKey = project.getEelApiKey()
|
||||
return Predicate { item ->
|
||||
ProjectSdksModel.sdkMatchesEel(eelApiKey, item.homePath)
|
||||
}
|
||||
}
|
||||
+1
@@ -76,6 +76,7 @@ public abstract class ModuleJdkConfigurable implements Disposable {
|
||||
final Project project = getRootModel().getModule().getProject();
|
||||
|
||||
Predicate<SdkTypeId> predicate = SimpleJavaSdkType.notSimpleJavaSdkType();
|
||||
// TODO Use EelApi here.
|
||||
myCbModuleJdk = new JdkComboBox(project, myJdksModel, predicate::test,
|
||||
WslSdkFilter.filterSdkByWsl(project), WslSdkFilter.filterSdkSuggestionByWsl(project),
|
||||
null, jdk -> {
|
||||
|
||||
+11
-2
@@ -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
|
||||
|
||||
+6
-1
@@ -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<MyNode> 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);
|
||||
}
|
||||
|
||||
+1
-2
@@ -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<List<String>>()
|
||||
runBackgroundableTask(ProjectBundle.message("progress.title.detecting.sdks"), project, false) { indicator ->
|
||||
val jdkVersions = mutableListOf<String>()
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.markdown.utils" />
|
||||
<orderEntry type="library" name="jetbrains.markdown" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.threadDumpParser" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel.provider" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ private class ExistingJdkConfigurationActivity : ProjectActivity {
|
||||
val rootManager = project.serviceAsync<ProjectRootManager>()
|
||||
val addedJdks = registeredJdks.toMutableList()
|
||||
|
||||
val priorityPaths = JavaHomeFinder.getFinder().findInJavaHome()
|
||||
val priorityPaths = JavaHomeFinder.getFinder(project).findInJavaHome()
|
||||
|
||||
writeAction {
|
||||
// Register collected JDKs
|
||||
|
||||
@@ -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<String> suggestHomePaths() {
|
||||
return JavaHomeFinder.suggestHomePaths();
|
||||
return suggestHomePaths(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<String> suggestHomePaths(@Nullable Project project) {
|
||||
return JavaHomeFinder.suggestHomePaths(EelProviderUtil.getEelApiBlocking(project), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<String> 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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* <a href="https://www.jetbrains.com/help/idea/sdk.html">SDK</a>. 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<String> suggestHomePaths() {
|
||||
String home = suggestHomePath();
|
||||
return ContainerUtil.createMaybeSingletonList(home);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all valid SDKs found on the host where {@code project} is located.
|
||||
* <p/>
|
||||
* E.g. for Python SDK on Unix the method may return {@code ["/usr/bin/python2", "/usr/bin/python3"]}.
|
||||
* <p/>
|
||||
* 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<String> 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}.
|
||||
|
||||
@@ -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<String> suggestHomePaths() {
|
||||
return suggestHomePaths(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<String> 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
|
||||
|
||||
@@ -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
|
||||
- <init>():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
|
||||
|
||||
@@ -107,5 +107,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.internal" />
|
||||
<orderEntry type="module" module-name="intellij.platform.concurrency" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel.provider" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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<String> suggestHomePaths() {
|
||||
return suggestHomePaths(false);
|
||||
}
|
||||
@@ -65,7 +75,22 @@ public abstract class JavaHomeFinder {
|
||||
* or that need the embedded JetBrains Runtime.
|
||||
*/
|
||||
public static @NotNull List<String> 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<String> suggestHomePaths(@NotNull EelApi eel, boolean forceEmbeddedJava) {
|
||||
JavaHomeFinderBasic javaFinder = getFinder(eel, forceEmbeddedJava);
|
||||
if (javaFinder == null) return Collections.emptyList();
|
||||
|
||||
ArrayList<String> 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) {
|
||||
|
||||
+2
-1
@@ -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<Path> paths = new HashSet<>();
|
||||
|
||||
if (myCheckDefaultInstallDir) {
|
||||
paths.add(JdkInstaller.getInstance().defaultInstallDir());
|
||||
paths.add(JdkInstaller.getInstance().defaultInstallDir((OsAbstractionForJdkInstaller)null));
|
||||
}
|
||||
|
||||
if (myCheckUsedInstallDirs) {
|
||||
|
||||
@@ -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<ScopeService>().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<Path> = 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<ScopeService>().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)
|
||||
}
|
||||
+15
-7
@@ -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<String>) -> CharSequence
|
||||
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
registeredJdks: Boolean,
|
||||
wslJdks: Boolean,
|
||||
systemInfoProvider: JavaHomeFinder.SystemInfoProvider,
|
||||
processRunner: (cmd: List<String>) -> 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<Path> = TreeSet()
|
||||
for (rp in registeredPaths) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+34
-12
@@ -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<ServiceScope>().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<JdkItem> by lazy {
|
||||
val lazyDownloadModel: SuspendingLazy<List<JdkItem>> = 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<JavaLocalSdkFix>()
|
||||
|
||||
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
|
||||
|
||||
+19
-3
@@ -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<JdkItem>, 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<WSLDistribution>,
|
||||
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<String>().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<String> {
|
||||
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)
|
||||
}
|
||||
|
||||
+33
-2
@@ -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<JdkDownloaderDialogHostExtension> = 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<EelApi, JdkDownloaderModel>? =
|
||||
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
|
||||
|
||||
|
||||
+108
-27
@@ -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<Path> = service<JdkInstallerStore>().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<String>, dir: String, timeout: Int): ProcessOutput {
|
||||
override fun execute(command: List<String>, 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<String>, 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<String>, dir: String, timeout: Int): ProcessOutput
|
||||
sealed interface OsAbstractionForJdkInstaller {
|
||||
fun getPath(path: Path): String
|
||||
fun execute(command: List<String>, 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<Path> = 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(
|
||||
|
||||
+94
@@ -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)
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -11,7 +11,7 @@ private val LOG = logger<JdkInstallerWSL>()
|
||||
|
||||
@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}"
|
||||
|
||||
+21
@@ -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"
|
||||
|
||||
+1
@@ -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)
|
||||
|
||||
+4
-5
@@ -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<RuntimeChooserJbrInstaller>()
|
||||
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)
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
+1
-2
@@ -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<RuntimeChooserJbrInstaller>().defaultInstallDir(item)
|
||||
return RuntimeChooserJbrInstaller.defaultInstallDir(item)
|
||||
}
|
||||
|
||||
private fun updateMainCombobox(newSelection: RuntimeChooserItem? = null) {
|
||||
|
||||
+25
-6
@@ -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<String> suggestedPaths = type.suggestHomePaths();
|
||||
Collection<String> suggestedPaths = type.suggestHomePaths(project);
|
||||
for (String path : suggestedPaths) {
|
||||
indicator.checkCanceled();
|
||||
|
||||
|
||||
+59
-3
@@ -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) {
|
||||
|
||||
+10
-8
@@ -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<String>, 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<String>, 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`() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -109,6 +109,8 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.diagnostic.telemetry.impl" />
|
||||
<orderEntry type="module" module-name="intellij.maven.server.telemetry" />
|
||||
<orderEntry type="library" name="ASM" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.eel.provider" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
|
||||
@@ -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<JdkFinder>().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<JdkFinder>().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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user