EA-220456 - do not search for SDKs from EDT (spoil - we almost do not)

ensure
SdkType#suggestHomePath does not do any heavy operations (it is used to show the file chooser dialog)

In fact, we use SdkType#suggestHomePaths for most of the cases, and it is called from a background thread.

This commit fixes the delegation - it is only allowed for the SdkType#suggestHomePaths to call the SdkType#suggestHomePath, not the opposite order. There were several cases of opposite delegation.

Also related to PY-41218

GitOrigin-RevId: d5716e81a35d33368812689eaadf4c11e2858e4f
This commit is contained in:
Eugene Petrenko
2020-03-21 20:01:57 +00:00
committed by intellij-monorepo-bot
parent deafca0214
commit 3e93352d6b
10 changed files with 80 additions and 39 deletions
@@ -1,4 +1,4 @@
// 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.
// 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.projectRoots.impl;
import com.intellij.icons.AllIcons;
@@ -189,8 +189,7 @@ public final class JavaSdkImpl extends JavaSdk {
@Override
public String suggestHomePath() {
Collection<String> paths = suggestHomePaths();
return paths.isEmpty() ? null : paths.iterator().next();
return JavaHomeFinder.defaultJavaLocation();
}
@NotNull
@@ -3,6 +3,7 @@ package com.intellij.openapi.projectRoots;
import com.intellij.openapi.application.ApplicationManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -12,9 +13,16 @@ public interface JdkFinder {
return ApplicationManager.getApplication().getService(JdkFinder.class);
}
/**
* @return a default install location for JDKs, ETD-friendly
*/
@Nullable
String defaultJavaLocation();
/**
* Tries to find existing Java SDKs on this computer.
* 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)
*/
@NotNull
@@ -1,9 +1,10 @@
// 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.
// 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.projectRoots;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.roots.OrderRootType;
@@ -39,6 +40,10 @@ public abstract class SdkType implements SdkTypeId {
* <p/>
* E.g. for Python SDK on Unix the method may return either {@code "/usr/bin"} or {@code "/usr/bin/python"}
* (if there is only one Python interpreter installed on a host).
* <p/>
* This method should work fast and allow running from the EDT thread. See the {@link #suggestHomePaths()}
* for more advanced scenarios
* @see #suggestHomePaths()
*/
@Nullable
public abstract String suggestHomePath();
@@ -47,6 +52,11 @@ public abstract class SdkType implements SdkTypeId {
* Returns a list of all valid SDKs found on this host.
* <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.
* @see #suggestHomePath()
*/
@NotNull
public Collection<String> suggestHomePaths() {
@@ -1,4 +1,4 @@
// 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.
// 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.projectRoots;
import com.intellij.openapi.project.ProjectBundle;
@@ -68,10 +68,10 @@ public class SimpleJavaSdkType extends SdkType implements JavaSdkType {
return new File(sdk.getHomePath(), "bin/java").getPath();
}
@Nullable
@Override
public String suggestHomePath() {
Collection<String> paths = suggestHomePaths();
return paths.isEmpty() ? null : paths.iterator().next();
return JdkFinder.getInstance().defaultJavaLocation();
}
@NotNull
@@ -6,6 +6,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.lang.JavaVersion;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -40,11 +41,12 @@ public abstract class JavaHomeFinder {
return paths;
}
private static boolean isDetectorEnabled(boolean forceEmbeddedJava) {
return forceEmbeddedJava || Registry.is("java.detector.enabled", true);
}
private static JavaHomeFinderBasic getFinder(boolean forceEmbeddedJava) {
boolean detectorIsEnabled = forceEmbeddedJava || Registry.is("java.detector.enabled", true);
if (!detectorIsEnabled) {
return null;
}
if (!isDetectorEnabled(forceEmbeddedJava)) return null;
if (SystemInfo.isWindows) {
return new JavaHomeFinderWindows(forceEmbeddedJava);
@@ -61,4 +63,24 @@ public abstract class JavaHomeFinder {
return new JavaHomeFinderBasic(forceEmbeddedJava);
}
@Nullable
public static String defaultJavaLocation() {
if (SystemInfo.isWindows) {
return JavaHomeFinderWindows.defaultJavaLocation;
}
if (SystemInfo.isMac) {
return JavaHomeFinderMac.defaultJavaLocation;
}
if (SystemInfo.isLinux) {
return "/opt/java";
}
if (SystemInfo.isSolaris) {
return "/usr/jdk";
}
return null;
}
}
@@ -14,9 +14,11 @@ import java.util.*;
class JavaHomeFinderMac extends JavaHomeFinderBasic {
public static final String JAVA_HOME_FIND_UTIL = "/usr/libexec/java_home";
static String defaultJavaLocation = "/Library/Java/JavaVirtualMachines";
JavaHomeFinderMac(boolean forceEmbeddedJava) {
super(forceEmbeddedJava,
"/Library/Java/JavaVirtualMachines",
defaultJavaLocation,
"/System/Library/Java/JavaVirtualMachines",
FileUtil.expandUserHome("~/Library/Java/JavaVirtualMachines")
);
@@ -15,6 +15,7 @@ import kotlin.text.RegexOption.MULTILINE
class JavaHomeFinderWindows : JavaHomeFinderBasic {
companion object {
const val defaultJavaLocation = "C:\\Program Files"
@Suppress("SpellCheckingInspection")
private const val regCommand = """reg query HKLM\SOFTWARE\JavaSoft\JDK /s /v JavaHome"""
@@ -39,7 +40,6 @@ class JavaHomeFinderWindows : JavaHomeFinderBasic {
}
return paths
}
}
constructor(forceEmbeddedJava: Boolean) : super(forceEmbeddedJava) {
@@ -3,6 +3,7 @@ package com.intellij.openapi.projectRoots.impl;
import com.intellij.openapi.projectRoots.JdkFinder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -12,4 +13,10 @@ public class JdkFinderImpl implements JdkFinder {
public List<String> suggestHomePaths() {
return JavaHomeFinder.suggestHomePaths();
}
@Nullable
@Override
public String defaultJavaLocation() {
return JavaHomeFinder.defaultJavaLocation();
}
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 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.projectRoots.impl;
import com.intellij.openapi.application.ApplicationManager;
@@ -249,10 +235,11 @@ public class SdkConfigurationUtil {
}
}
for (SdkType sdkType : sdkTypes) {
final String suggestedHomePath = sdkType.suggestHomePath();
if (suggestedHomePath != null && sdkType.isValidSdkHome(suggestedHomePath)) {
Sdk an_sdk = createAndAddSDK(suggestedHomePath, sdkType);
if (an_sdk != null) return an_sdk;
for(String suggestedHomePath : sdkType.suggestHomePaths()) {
if (sdkType.isValidSdkHome(suggestedHomePath)) {
Sdk an_sdk = createAndAddSDK(suggestedHomePath, sdkType);
if (an_sdk != null) return an_sdk;
}
}
}
return null;
@@ -1,4 +1,4 @@
// 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.
// 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.jetbrains.python.sdk;
import com.google.common.collect.Lists;
@@ -13,6 +13,7 @@ import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
@@ -58,10 +59,8 @@ import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
@@ -121,13 +120,20 @@ public final class PythonSdkType extends SdkType {
@NonNls
@Nullable
public String suggestHomePath() {
final Sdk[] existingSdks = ProjectJdkTable.getInstance().getAllJdks();
return null;
}
@NotNull
@Override
public Collection<String> suggestHomePaths() {
final Sdk[] existingSdks = ReadAction.compute(() -> ProjectJdkTable.getInstance().getAllJdks());
final List<PyDetectedSdk> sdks = PySdkExtKt.detectSystemWideSdks(null, Arrays.asList(existingSdks));
//return all detected items after PY-41218 is fixed
final PyDetectedSdk latest = StreamEx.of(sdks).findFirst().orElse(null);
if (latest != null) {
return latest.getHomePath();
return Collections.singleton(latest.getHomePath());
}
return null;
return Collections.emptyList();
}
@Override