diff --git a/java/idea-ui/src/com/intellij/jdkDownloader/JdkAuto.kt b/java/idea-ui/src/com/intellij/jdkDownloader/JdkAuto.kt index 34585bd6770c..e6897362e354 100644 --- a/java/idea-ui/src/com/intellij/jdkDownloader/JdkAuto.kt +++ b/java/idea-ui/src/com/intellij/jdkDownloader/JdkAuto.kt @@ -7,9 +7,8 @@ import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.* -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.* -import com.intellij.openapi.roots.ui.configuration.SdkDetector +import com.intellij.openapi.roots.ui.configuration.* +import com.intellij.openapi.roots.ui.configuration.UnknownSdkResolver.* import com.intellij.openapi.roots.ui.configuration.SdkDetector.DetectedSdkListener import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTask import com.intellij.openapi.util.registry.Registry @@ -31,7 +30,7 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase { JdkListDownloader.downloadModelForJdkInstaller(indicator) } - override fun proposeDownload(sdk: UnknownSdk, indicator: ProgressIndicator): DownloadSdkFix? { + override fun proposeDownload(sdk: UnknownSdk, indicator: ProgressIndicator): UnknownSdkDownloadableSdkFix? { if (sdk.sdkType != sdkType) return null val req = JdkRequirements.parseRequirement(sdk) ?: return null @@ -49,7 +48,7 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase { }.maxBy { it.second } ?.first ?: return null - return object: DownloadSdkFix { + return object: UnknownSdkDownloadableSdkFix { override fun getDownloadDescription() = jdkToDownload.fullPresentationText override fun createTask(indicator: ProgressIndicator): SdkDownloadTask { @@ -75,7 +74,7 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase { result } - override fun proposeLocalFix(sdk: UnknownSdk, indicator: ProgressIndicator): LocalSdkFix? { + override fun proposeLocalFix(sdk: UnknownSdk, indicator: ProgressIndicator): UnknownSdkLocalSdkFix? { if (sdk.sdkType != sdkType) return null val req = JdkRequirements.parseRequirement(sdk) ?: return null @@ -107,7 +106,7 @@ class JdkAuto : UnknownSdkResolver, JdkDownloaderBase { private class JavaLocalSdkFix(val homeDir: String, val version: JavaVersion, - val suggestedName: String) : LocalSdkFix { + val suggestedName: String) : UnknownSdkLocalSdkFix { override fun getExistingSdkHome() = homeDir override fun getVersionString() = JdkVersionDetector.formatVersionString(version) override fun getSuggestedSdkName() : String = suggestedName diff --git a/java/idea-ui/src/com/intellij/jdkDownloader/JdkRequirement.kt b/java/idea-ui/src/com/intellij/jdkDownloader/JdkRequirement.kt index 8cd535cb6c8f..5660b26d2ba4 100644 --- a/java/idea-ui/src/com/intellij/jdkDownloader/JdkRequirement.kt +++ b/java/idea-ui/src/com/intellij/jdkDownloader/JdkRequirement.kt @@ -3,7 +3,7 @@ package com.intellij.jdkDownloader import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.UnknownSdk +import com.intellij.openapi.roots.ui.configuration.UnknownSdk import com.intellij.util.lang.JavaVersion diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkBalloonNotification.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkBalloonNotification.java index 71260192a0a4..5bea0dea145d 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkBalloonNotification.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkBalloonNotification.java @@ -7,6 +7,8 @@ import com.intellij.notification.NotificationType; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; import com.intellij.openapi.roots.ui.configuration.SdkListPresenter; +import com.intellij.openapi.roots.ui.configuration.UnknownSdk; +import com.intellij.openapi.roots.ui.configuration.UnknownSdkLocalSdkFix; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; @@ -15,7 +17,6 @@ import java.util.Set; import java.util.TreeSet; import static com.intellij.notification.NotificationAction.createSimple; -import static com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.*; public class UnknownSdkBalloonNotification { private static final NotificationGroup SDK_CONFIGURED_GROUP @@ -32,7 +33,7 @@ public class UnknownSdkBalloonNotification { myProject = project; } - public void notifyFixedSdks(@NotNull Map localFixes) { + public void notifyFixedSdks(@NotNull Map localFixes) { if (localFixes.isEmpty()) return; final String title; @@ -40,8 +41,8 @@ public class UnknownSdkBalloonNotification { final StringBuilder message = new StringBuilder(); Set usages = new TreeSet<>(); - for (Map.Entry entry : localFixes.entrySet()) { - LocalSdkFix fix = entry.getValue(); + for (Map.Entry entry : localFixes.entrySet()) { + UnknownSdkLocalSdkFix fix = entry.getValue(); String usage = "\"" + entry.getKey().getSdkName() + "\"" + " is set to " + fix.getVersionString() + @@ -52,7 +53,7 @@ public class UnknownSdkBalloonNotification { message.append(StringUtil.join(usages, "

")); if (localFixes.size() == 1) { - Map.Entry entry = localFixes.entrySet().iterator().next(); + Map.Entry entry = localFixes.entrySet().iterator().next(); UnknownSdk info = entry.getKey(); String sdkTypeName = info.getSdkType().getPresentableName(); title = sdkTypeName + " is configured"; diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkCollector.kt b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkCollector.kt index b8d88d8c7a33..63307c003528 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkCollector.kt +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkCollector.kt @@ -8,7 +8,7 @@ import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.progress.ProgressManager.checkCanceled import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.SdkType -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.UnknownSdk +import com.intellij.openapi.roots.ui.configuration.UnknownSdk import com.intellij.openapi.roots.ModuleJdkOrderEntry import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ProjectRootManager diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkEditorNotification.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkEditorNotification.java index 3d305357a63d..f27400abfedf 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkEditorNotification.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkEditorNotification.java @@ -11,8 +11,8 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.SdkType; -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.DownloadSdkFix; -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.UnknownSdk; +import com.intellij.openapi.roots.ui.configuration.UnknownSdk; +import com.intellij.openapi.roots.ui.configuration.UnknownSdkDownloadableSdkFix; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotificationPanel; @@ -83,7 +83,7 @@ public class UnknownSdkEditorNotification implements Disposable { public void showNotifications(boolean allowProjectSdkValidation, @NotNull Map unifiableSdkNames, - @NotNull Map files) { + @NotNull Map files) { ImmutableSet.Builder notifications = ImmutableSet.builder(); for (Map.Entry e : unifiableSdkNames.entrySet()) { String name = e.getKey(); @@ -91,7 +91,7 @@ public class UnknownSdkEditorNotification implements Disposable { notifications.add(new SimpleSdkFixInfo(name, type)); } - for (Map.Entry e : files.entrySet()) { + for (Map.Entry e : files.entrySet()) { notifications.add(new SimpleSdkFixInfo(e.getKey(), e.getValue())); } @@ -144,7 +144,7 @@ public class UnknownSdkEditorNotification implements Disposable { private final String mySdkName; @Nullable private final SdkType mySdkType; @Nullable private final UnknownSdk mySdk; - @Nullable private final DownloadSdkFix myFix; + @Nullable private final UnknownSdkDownloadableSdkFix myFix; SimpleSdkFixInfo(String sdkName, @Nullable SdkType sdkType) { mySdkName = sdkName; @@ -153,7 +153,7 @@ public class UnknownSdkEditorNotification implements Disposable { myFix = null; } - SimpleSdkFixInfo(@NotNull UnknownSdk sdk, @NotNull DownloadSdkFix fix) { + SimpleSdkFixInfo(@NotNull UnknownSdk sdk, @NotNull UnknownSdkDownloadableSdkFix fix) { mySdkName = sdk.getSdkName(); mySdkType = sdk.getSdkType(); mySdk = sdk; diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkResolver.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkResolver.java deleted file mode 100644 index a524e1244dd7..000000000000 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkResolver.java +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.openapi.projectRoots.impl; - -import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.SdkType; -import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTask; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Extension point to resolve missing SDKs in a project, - * it is executed from a background thread on project open - * or after project model changes - */ -public interface UnknownSdkResolver { - @ApiStatus.Internal - ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.unknownSdkResolver"); - - /** - * Creates search context. The same object is used to process all unknown SDKs in the project, - * it a good idea to cache any heavy operations inside that instance. - * That method must be cheap to run. - *
- * Return {@code null} to ignore a given request - */ - @Nullable - UnknownSdkLookup createResolver(@Nullable Project project, @NotNull ProgressIndicator indicator); - - interface UnknownSdkLookup { - /** - * The implementation should check on a local machine (both in existing SDKs and on the disk) - * for a possible matching SDK - * - * @return best match or {@code null} if there is no fix found - */ - @Nullable - LocalSdkFix proposeLocalFix(@NotNull UnknownSdk sdk, @NotNull ProgressIndicator indicator); - - /** - * Checks the internet for a possible download to fix the SDK. - * - * @return the best possible download for {@link com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTracker}, - * or {@code null} if there is no fix found - */ - @Nullable - DownloadSdkFix proposeDownload(@NotNull UnknownSdk sdk, @NotNull ProgressIndicator indicator); - } - - /** - * Contains information and requirements for the SDK to resolve - */ - @ApiStatus.NonExtendable - interface UnknownSdk { - /** - * Type of SDK to resolve with {@link UnknownSdkLookup} - */ - @NotNull - SdkType getSdkType(); - - /** - * A missing SDK name, if known. A detector implementation may rely on the naming - * to use it for a better decision on the SDK to suggest. - */ - @Nullable - default String getSdkName() { return null; } - - /** - * A minimum version (inclusive) of a resolved SDK. - * {@link SdkType#versionComparator()} will be used for comparison. - */ - @Nullable - default String getSdkMinVersionRequirement() { return null; } - - /** - * A maximum version (exclusive) of a resolved SDK. - * {@link SdkType#versionComparator()} will be used for comparison. - */ - @Nullable - default String getSdkMaxVersionRequirement() { return null; } - } - - /** - * Locally detected SDK to fix immediately - */ - interface LocalSdkFix { - /** - * @return the resolved home of the detected SDK to configure - */ - @NotNull String getExistingSdkHome(); - - /** - * @return the actual version string of the SDK - */ - @NotNull String getVersionString(); - - /** - * @return suggested name for an SDK to be created, still, the name could - * be altered to avoid conflicts - */ - @NotNull - String getSuggestedSdkName(); - } - - /** - * A download suggestion to fix a missing SDK by downloading it - * @see com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownload - */ - interface DownloadSdkFix { - @NotNull - String getDownloadDescription(); - - @NotNull - SdkDownloadTask createTask(@NotNull ProgressIndicator indicator); - } -} diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkTracker.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkTracker.java index 43e1c31afaec..409f6161d9bb 100644 --- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkTracker.java +++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/UnknownSdkTracker.java @@ -15,10 +15,9 @@ import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.projectRoots.SdkType; -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.DownloadSdkFix; -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.LocalSdkFix; -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.UnknownSdkLookup; -import com.intellij.openapi.roots.ui.configuration.SdkPopupFactory; +import com.intellij.openapi.roots.ui.configuration.*; +import com.intellij.openapi.roots.ui.configuration.UnknownSdkDownloadableSdkFix; +import com.intellij.openapi.roots.ui.configuration.UnknownSdkResolver.UnknownSdkLookup; import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTask; import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTracker; import com.intellij.openapi.ui.Messages; @@ -37,7 +36,6 @@ import javax.swing.*; import java.util.*; import static com.intellij.openapi.progress.PerformInBackgroundOption.ALWAYS_BACKGROUND; -import static com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.UnknownSdk; public class UnknownSdkTracker implements Disposable { private static final Logger LOG = Logger.getInstance(UnknownSdkTracker.class); @@ -99,10 +97,10 @@ public class UnknownSdkTracker implements Disposable { List lookups = collectSdkLookups(indicator); indicator.setText("Looking for local SDKs..."); - Map localFixes = findFixesAndRemoveFixable(indicator, fixable, lookups, UnknownSdkLookup::proposeLocalFix); + Map localFixes = findFixesAndRemoveFixable(indicator, fixable, lookups, UnknownSdkLookup::proposeLocalFix); indicator.setText("Looking for downloadable SDKs..."); - Map downloadFixes = findFixesAndRemoveFixable(indicator, fixable, lookups, UnknownSdkLookup::proposeDownload); + Map downloadFixes = findFixesAndRemoveFixable(indicator, fixable, lookups, UnknownSdkLookup::proposeDownload); fixable.forEach(it -> missingSdks.put(it.getSdkName(), it.getSdkType())); if (!localFixes.isEmpty()) { @@ -117,8 +115,8 @@ public class UnknownSdkTracker implements Disposable { } private void showStatus(@NotNull Map missingSdks, - @NotNull Map localFixes, - @NotNull Map downloadFixes) { + @NotNull Map localFixes, + @NotNull Map downloadFixes) { UnknownSdkBalloonNotification .getInstance(myProject) .notifyFixedSdks(localFixes); @@ -150,7 +148,7 @@ public class UnknownSdkTracker implements Disposable { return lookups; } - public void applyDownloadableFix(@NotNull UnknownSdk info, @NotNull DownloadSdkFix fix) { + public void applyDownloadableFix(@NotNull UnknownSdk info, @NotNull UnknownSdkDownloadableSdkFix fix) { downloadFix(myProject, info, fix, sdk -> { if (sdk != null) { updateUnknownSdks(); @@ -161,7 +159,7 @@ public class UnknownSdkTracker implements Disposable { @ApiStatus.Internal public static void downloadFix(@Nullable Project project, @NotNull UnknownSdk info, - @NotNull DownloadSdkFix fix, + @NotNull UnknownSdkDownloadableSdkFix fix, @NotNull Consumer onCompleted) { SdkDownloadTask task; String title = "Configuring SDK"; @@ -229,12 +227,12 @@ public class UnknownSdkTracker implements Disposable { .showUnderneathToTheRightOf(underneathRightOfComponent); } - private void configureLocalSdks(@NotNull Map localFixes) { + private void configureLocalSdks(@NotNull Map localFixes) { if (localFixes.isEmpty()) return; - for (Map.Entry e : localFixes.entrySet()) { + for (Map.Entry e : localFixes.entrySet()) { UnknownSdk info = e.getKey(); - LocalSdkFix fix = e.getValue(); + UnknownSdkLocalSdkFix fix = e.getValue(); configureLocalSdk(info, fix, sdk -> {}); } @@ -244,7 +242,7 @@ public class UnknownSdkTracker implements Disposable { @ApiStatus.Internal public static void configureLocalSdk(@NotNull UnknownSdk info, - @NotNull LocalSdkFix fix, + @NotNull UnknownSdkLocalSdkFix fix, @NotNull Consumer onCompleted) { ApplicationManager.getApplication().invokeLater(() -> { try { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkLookup.kt b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkLookup.kt index 42d12ea6505a..7c2eee78632c 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkLookup.kt +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkLookup.kt @@ -12,13 +12,12 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.SdkType -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver -import com.intellij.openapi.projectRoots.impl.UnknownSdkResolver.* import com.intellij.openapi.projectRoots.impl.UnknownSdkTracker import com.intellij.openapi.roots.ProjectRootManager import com.intellij.util.Consumer import org.jetbrains.annotations.Contract import org.jetbrains.annotations.Nls +import java.util.function.Predicate /** @@ -52,8 +51,8 @@ data class SdkLookupBuilder private constructor( val sdkMinVersionInclusive: String? = null, val sdkMaxVersionExclusive: String? = null, - val onLocalSdkSuggested: ((LocalSdkFix) -> Boolean)? = null, - val onDownloadableSdkSuggested: ((DownloadSdkFix) -> Boolean)? = null, + val onLocalSdkSuggested: ((UnknownSdkLocalSdkFix) -> Boolean)? = null, + val onDownloadableSdkSuggested: ((UnknownSdkDownloadableSdkFix) -> Boolean)? = null, /** * The [Sdk#sdkType] may not match the proposed [sdkType] if the @@ -78,8 +77,8 @@ data class SdkLookupBuilder private constructor( @Contract(pure = true) fun withMinSdkVersionInclusive(version: String) = copy(sdkMinVersionInclusive = version) @Contract(pure = true) fun withMaxSdkVersionExclusive(version: String) = copy(sdkMaxVersionExclusive = version) - @Contract(pure = true) fun onLocalSdkSuggested(handler: (LocalSdkFix) -> Boolean) = copy(onLocalSdkSuggested = handler) - @Contract(pure = true) fun onDownloadableSdkSuggested(handler: (DownloadSdkFix) -> Boolean) = copy(onDownloadableSdkSuggested = handler) + @Contract(pure = true) fun onLocalSdkSuggested(handler: (UnknownSdkLocalSdkFix) -> Boolean) = copy(onLocalSdkSuggested = handler) + @Contract(pure = true) fun onDownloadableSdkSuggested(handler: (UnknownSdkDownloadableSdkFix) -> Boolean) = copy(onDownloadableSdkSuggested = handler) @Contract(pure = true) fun onSdkResolved(handler: (Sdk?) -> Unit) = copy(onSdkResolved = handler) fun lookup() = service().lookup(copy()) @@ -119,10 +118,21 @@ internal class SdkLookupImpl : SdkLookup { return } + val versionPredicate = if (sdkMinVersionInclusive != null || sdkMaxVersionExclusive != null) { + val vCmp = sdkType.versionStringComparator() + Predicate { version -> + ((sdkMinVersionInclusive == null || vCmp.compare(sdkMinVersionInclusive, version) <= 0)) + && + ((sdkMaxVersionExclusive == null || vCmp.compare(version, sdkMaxVersionExclusive) > 0)) + } + } else { + Predicate { true } + } + val unknownSdk = object: UnknownSdk { - override fun getSdkMinVersionRequirement() = this@run.sdkMinVersionInclusive - override fun getSdkMaxVersionRequirement() = this@run.sdkMaxVersionExclusive override fun getSdkType() : SdkType = this@run.sdkType + override fun getSdkVersionStringPredicate() = versionPredicate + override fun toString() = "SdkLookup{${sdkType.presentableName}, version in [$sdkMinVersionInclusive, $sdkMaxVersionExclusive) }" } runWithProgress(onCancelled = { onSdkResolved?.invoke(null) }) { indicator -> diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdk.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdk.java new file mode 100644 index 000000000000..5f179c50aa24 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdk.java @@ -0,0 +1,41 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.roots.ui.configuration; + +import com.google.common.base.Predicates; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Predicate; + +/** + * Contains information and requirements for an SDK to resolve + * with {@link UnknownSdkResolver} extension + */ +public interface UnknownSdk { + /** + * Type of SDK to resolve with {@link UnknownSdkResolver.UnknownSdkLookup} + */ + @NotNull + SdkType getSdkType(); + + /** + * A missing SDK name, if known. A detector implementation may rely on the naming + * to use it for a better decision on the SDK to suggest. + */ + @Nullable + default String getSdkName() { return null; } + + /** + * Condition to test a possible SDK candidates to match version + * predicate. We use {@link SdkType#getVersionString(Sdk)} or + * {@link Sdk#getVersionString()} to get versions in most of the cases. + *
+ * Use the {@link SdkType#versionComparator()} to better deal with versions comparison + */ + @NotNull + default Predicate getSdkVersionStringPredicate() { + return Predicates.alwaysTrue(); + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkDownloadableSdkFix.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkDownloadableSdkFix.java new file mode 100644 index 000000000000..32bcce8f9743 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkDownloadableSdkFix.java @@ -0,0 +1,24 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.roots.ui.configuration; + +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTask; +import org.jetbrains.annotations.NotNull; + +/** + * A download suggestion to fix a missing SDK by downloading it + * @see com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownload + */ +public interface UnknownSdkDownloadableSdkFix { + /** User visible description of the proposed download **/ + @NotNull + String getDownloadDescription(); + + /** + * Creates and SDK download task to apply the fix. + * @see com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownload + * @see com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTracker + */ + @NotNull + SdkDownloadTask createTask(@NotNull ProgressIndicator indicator); +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkLocalSdkFix.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkLocalSdkFix.java new file mode 100644 index 000000000000..8e845f1418d3 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkLocalSdkFix.java @@ -0,0 +1,27 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.roots.ui.configuration; + +import org.jetbrains.annotations.NotNull; + +/** + * Locally detected SDK to fix immediately + */ +public interface UnknownSdkLocalSdkFix { + /** + * @return the resolved home of the detected SDK to configure + */ + @NotNull + String getExistingSdkHome(); + + /** + * @return the actual version string of the SDK + */ + @NotNull String getVersionString(); + + /** + * @return suggested name for an SDK to be created, still, the name could + * be altered to avoid conflicts + */ + @NotNull + String getSuggestedSdkName(); +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkResolver.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkResolver.java new file mode 100644 index 000000000000..33862440620f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/UnknownSdkResolver.java @@ -0,0 +1,49 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.roots.ui.configuration; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Extension point to resolve missing SDKs in a project, + * it is executed from a background thread on project open + * or after project model changes + */ +public interface UnknownSdkResolver { + @ApiStatus.Internal + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.unknownSdkResolver"); + + /** + * Creates search context. The same object is used to process all unknown SDKs in the project, + * it a good idea to cache any heavy operations inside that instance. + * That method must be cheap to run. + *
+ * Return {@code null} to ignore a given request + */ + @Nullable + UnknownSdkLookup createResolver(@Nullable Project project, @NotNull ProgressIndicator indicator); + + interface UnknownSdkLookup { + /** + * The implementation should check on a local machine (both in existing SDKs and on the disk) + * for a possible matching SDK + * + * @return best match or {@code null} if there is no fix found + */ + @Nullable + UnknownSdkLocalSdkFix proposeLocalFix(@NotNull UnknownSdk sdk, @NotNull ProgressIndicator indicator); + + /** + * Checks the internet for a possible download to fix the SDK. + * + * @return the best possible download for {@link com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTracker}, + * or {@code null} if there is no fix found + */ + @Nullable + UnknownSdkDownloadableSdkFix proposeDownload(@NotNull UnknownSdk sdk, @NotNull ProgressIndicator indicator); + } +} diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 04a948245903..468f34ab852b 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -353,7 +353,7 @@ - +