diff --git a/python/gen/icons/PythonIcons.java b/python/gen/icons/PythonIcons.java index 96603fa94042..a5948cb713df 100644 --- a/python/gen/icons/PythonIcons.java +++ b/python/gen/icons/PythonIcons.java @@ -42,6 +42,7 @@ public class PythonIcons { public static final Icon Buildout = load("/icons/com/jetbrains/python/buildout/buildout.png"); // 16x16 } + public static final Icon Condaenv = load("/icons/com/jetbrains/python/condaenv.png"); // 16x16 public static final Icon DataView = load("/icons/com/jetbrains/python/DataView.png"); // 13x13 public static class Debug { diff --git a/python/python-community-configure/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java b/python/python-community-configure/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java index a3a221f96020..b57a729c9198 100644 --- a/python/python-community-configure/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java +++ b/python/python-community-configure/src/com/jetbrains/python/configuration/PyConfigurableInterpreterList.java @@ -26,6 +26,7 @@ import com.jetbrains.python.sdk.PyDetectedSdk; import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkAdditionalData; import com.jetbrains.python.sdk.PythonSdkType; +import com.jetbrains.python.sdk.flavors.CondaEnvSdkFlavor; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor; import org.jetbrains.annotations.NotNull; @@ -79,8 +80,9 @@ public class PyConfigurableInterpreterList { private void addDetectedSdks(@NotNull final List result) { final List sdkHomes = new ArrayList<>(); sdkHomes.addAll(VirtualEnvSdkFlavor.INSTANCE.suggestHomePaths()); + sdkHomes.addAll(CondaEnvSdkFlavor.INSTANCE.suggestHomePaths()); for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { - if (flavor instanceof VirtualEnvSdkFlavor) continue; + if (flavor instanceof VirtualEnvSdkFlavor || flavor instanceof CondaEnvSdkFlavor) continue; sdkHomes.addAll(flavor.suggestHomePaths()); } Collections.sort(sdkHomes); diff --git a/python/resources/icons/com/jetbrains/python/condaenv.png b/python/resources/icons/com/jetbrains/python/condaenv.png new file mode 100644 index 000000000000..8681282f0d52 Binary files /dev/null and b/python/resources/icons/com/jetbrains/python/condaenv.png differ diff --git a/python/resources/icons/com/jetbrains/python/condaenv@2x.png b/python/resources/icons/com/jetbrains/python/condaenv@2x.png new file mode 100644 index 000000000000..d3d752947012 Binary files /dev/null and b/python/resources/icons/com/jetbrains/python/condaenv@2x.png differ diff --git a/python/resources/icons/com/jetbrains/python/condaenv_dark.png b/python/resources/icons/com/jetbrains/python/condaenv_dark.png new file mode 100644 index 000000000000..7e983a1f419e Binary files /dev/null and b/python/resources/icons/com/jetbrains/python/condaenv_dark.png differ diff --git a/python/resources/icons/com/jetbrains/python/condaenv_dark@2x.png b/python/resources/icons/com/jetbrains/python/condaenv_dark@2x.png new file mode 100644 index 000000000000..5ed486884ef0 Binary files /dev/null and b/python/resources/icons/com/jetbrains/python/condaenv_dark@2x.png differ diff --git a/python/src/com/jetbrains/python/packaging/PyCondaPackageService.java b/python/src/com/jetbrains/python/packaging/PyCondaPackageService.java index 29f3e5a70cdd..a6f8be202e3d 100644 --- a/python/src/com/jetbrains/python/packaging/PyCondaPackageService.java +++ b/python/src/com/jetbrains/python/packaging/PyCondaPackageService.java @@ -30,7 +30,7 @@ import com.intellij.util.xmlb.XmlSerializerUtil; import com.jetbrains.python.PythonHelpersLocator; import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkType; -import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor; +import com.jetbrains.python.sdk.flavors.CondaEnvSdkFlavor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -132,7 +132,7 @@ public class PyCondaPackageService implements PersistentStateComponent locations = VirtualEnvSdkFlavor.getCondaDefaultLocations(); + final List locations = CondaEnvSdkFlavor.getCondaDefaultLocations(); if (!locations.isEmpty()) { myInitialPath = locations.get(0).getPath(); return; diff --git a/python/src/com/jetbrains/python/sdk/flavors/CondaEnvSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/CondaEnvSdkFlavor.java new file mode 100644 index 000000000000..1f9baad43ac0 --- /dev/null +++ b/python/src/com/jetbrains/python/sdk/flavors/CondaEnvSdkFlavor.java @@ -0,0 +1,115 @@ +/* + * Copyright 2000-2017 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. + */ +package com.jetbrains.python.sdk.flavors; + +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.SystemProperties; +import com.jetbrains.python.sdk.PythonSdkType; +import icons.PythonIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor.findInDirectory; + +public class CondaEnvSdkFlavor extends CPythonSdkFlavor { + private CondaEnvSdkFlavor() { + } + + public final static String[] CONDA_DEFAULT_ROOTS = new String[]{"anaconda", "anaconda2", "anaconda3", "miniconda", "miniconda2", + "miniconda3", "Anaconda", "Anaconda2", "Anaconda3", "Miniconda", "Miniconda2", "Miniconda3"}; + + public static CondaEnvSdkFlavor INSTANCE = new CondaEnvSdkFlavor(); + + @Override + public Collection suggestHomePaths() { + List candidates = new ArrayList<>(); + + for (VirtualFile file : getCondaDefaultLocations()) { + candidates.addAll(findInDirectory(file)); + } + + return candidates; + } + + public static List getCondaDefaultLocations() { + List roots = new ArrayList<>(); + final VirtualFile userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\','/')); + if (userHome != null) { + final VirtualFile condaHidden = userHome.findChild(".conda"); + if (condaHidden != null) { + addEnvsFolder(roots, condaHidden); + } + for (String root : CONDA_DEFAULT_ROOTS) { + VirtualFile condaFolder = userHome.findChild(root); + addEnvsFolder(roots, condaFolder); + if (SystemInfo.isWindows) { + final VirtualFile appData = userHome.findFileByRelativePath("AppData\\Local\\Continuum\\" + root); + addEnvsFolder(roots, appData); + condaFolder = LocalFileSystem.getInstance().findFileByPath("C:\\" + root); + addEnvsFolder(roots, condaFolder); + } + else { + final String systemWidePath = "/opt/anaconda"; + condaFolder = LocalFileSystem.getInstance().findFileByPath(systemWidePath); + addEnvsFolder(roots, condaFolder); + } + } + } + return roots; + } + + private static void addEnvsFolder(@NotNull final List roots, @Nullable final VirtualFile condaFolder) { + if (condaFolder != null) { + final VirtualFile envs = condaFolder.findChild("envs"); + if (envs != null) { + roots.add(envs); + } + } + } + + @Override + public boolean isValidSdkPath(@NotNull File file) { + if (!super.isValidSdkPath(file)) return false; + final File bin = file.getParentFile(); + String condaName = "conda"; + if (SystemInfo.isWindows) { + condaName = new File(bin, "envs").exists() ? "conda.exe" : "conda.bat"; + } + if (bin != null) { + final File conda = new File(bin, condaName); + if (conda.exists()) { + return true; + } + final File condaFolder = bin.getParentFile(); + final File condaExecutable = PythonSdkType.findExecutableFile(condaFolder, condaName); + if (condaExecutable != null) return true; + } + return false; + } + + @Override + public Icon getIcon() { + return PythonIcons.Python.Condaenv; + } +} diff --git a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java index 5181beb33af4..414d3646c0bb 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java @@ -117,6 +117,7 @@ public abstract class PythonSdkFlavor { result.add(IronPythonSdkFlavor.INSTANCE); result.add(PyPySdkFlavor.INSTANCE); result.add(VirtualEnvSdkFlavor.INSTANCE); + result.add(CondaEnvSdkFlavor.INSTANCE); result.add(PyRemoteSdkFlavor.INSTANCE); return result; diff --git a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java index c931f54c9648..3034a11072b1 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java @@ -42,8 +42,6 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { private VirtualEnvSdkFlavor() { } private final static String[] NAMES = new String[]{"jython", "pypy", "python.exe", "jython.bat", "pypy.exe"}; - public final static String[] CONDA_DEFAULT_ROOTS = new String[]{"anaconda", "anaconda2", "anaconda3", "miniconda", "miniconda2", - "miniconda3", "Anaconda", "Anaconda2", "Anaconda3", "Miniconda", "Miniconda2", "Miniconda3"}; public static VirtualEnvSdkFlavor INSTANCE = new VirtualEnvSdkFlavor(); @@ -61,10 +59,6 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { if (path != null) candidates.addAll(findInDirectory(path)); - for (VirtualFile file : getCondaDefaultLocations()) { - candidates.addAll(findInDirectory(file)); - } - final VirtualFile pyEnvLocation = getPyEnvDefaultLocations(); if (pyEnvLocation != null) { candidates.addAll(findInDirectory(pyEnvLocation)); @@ -88,42 +82,6 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { return null; } - public static List getCondaDefaultLocations() { - List roots = new ArrayList<>(); - final VirtualFile userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\','/')); - if (userHome != null) { - final VirtualFile condaHidden = userHome.findChild(".conda"); - if (condaHidden != null) { - addEnvsFolder(roots, condaHidden); - } - for (String root : CONDA_DEFAULT_ROOTS) { - VirtualFile condaFolder = userHome.findChild(root); - addEnvsFolder(roots, condaFolder); - if (SystemInfo.isWindows) { - final VirtualFile appData = userHome.findFileByRelativePath("AppData\\Local\\Continuum\\" + root); - addEnvsFolder(roots, appData); - condaFolder = LocalFileSystem.getInstance().findFileByPath("C:\\" + root); - addEnvsFolder(roots, condaFolder); - } - else { - final String systemWidePath = "/opt/anaconda"; - condaFolder = LocalFileSystem.getInstance().findFileByPath(systemWidePath); - addEnvsFolder(roots, condaFolder); - } - } - } - return roots; - } - - private static void addEnvsFolder(@NotNull final List roots, @Nullable final VirtualFile condaFolder) { - if (condaFolder != null) { - final VirtualFile envs = condaFolder.findChild("envs"); - if (envs != null) { - roots.add(envs); - } - } - } - public static VirtualFile getDefaultLocation() { final String path = System.getenv().get("WORKON_HOME"); if (!StringUtil.isEmpty(path)) {