mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-9081 PY-12247 PY-26492 Associate interpreters with modules, not with projects
This commit is contained in:
@@ -75,7 +75,7 @@ public class PythonSdkConfigurator implements DirectoryProjectConfigurator {
|
||||
additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(virtualEnvSdk.getHomePath()));
|
||||
((ProjectJdkImpl)virtualEnvSdk).setSdkAdditionalData(additionalData);
|
||||
}
|
||||
((PythonSdkAdditionalData) additionalData).associateWithProject(project);
|
||||
((PythonSdkAdditionalData) additionalData).setAssociatedModulePath(project.getBasePath());
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ public class EditSdkDialog extends DialogWrapper {
|
||||
if ((sdkFlavor instanceof VirtualEnvSdkFlavor) || (sdkFlavor instanceof CondaEnvSdkFlavor)) {
|
||||
PythonSdkAdditionalData data = (PythonSdkAdditionalData) sdk.getSdkAdditionalData();
|
||||
if (data != null) {
|
||||
final String path = data.getAssociatedProjectPath();
|
||||
final String path = data.getAssociatedModulePath();
|
||||
if (path != null) {
|
||||
myAssociateCheckbox.setSelected(true);
|
||||
final String basePath = project.getBasePath();
|
||||
|
||||
+2
-2
@@ -214,7 +214,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable {
|
||||
? new PythonSdkDetailsDialog(myProject, myAddSdkCallback, getSettingsModifiedCallback())
|
||||
: new PythonSdkDetailsDialog(myModule, myAddSdkCallback, getSettingsModifiedCallback());
|
||||
|
||||
PythonSdkDetailsStep.show(myProject, myProjectSdksModel.getSdks(), allDialog, myMainPanel,
|
||||
PythonSdkDetailsStep.show(myProject, myModule, myProjectSdksModel.getSdks(), allDialog, myMainPanel,
|
||||
myDetailsButton.getLocationOnScreen(), null, myAddSdkCallback);
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable {
|
||||
final List<Sdk> allPythonSdks = myInterpreterList.getAllPythonSdks(myProject);
|
||||
final List<Sdk> visibleSdks = StreamEx
|
||||
.of(allPythonSdks)
|
||||
.filter(sdk -> !PythonSdkType.isInvalid(sdk) && !PySdkExtKt.isAssociatedWithAnotherProject(sdk, myProject))
|
||||
.filter(sdk -> !PythonSdkType.isInvalid(sdk) && !PySdkExtKt.isAssociatedWithAnotherModule(sdk, myModule))
|
||||
.toList();
|
||||
final LinkedHashSet<Sdk> virtualEnvironments = StreamEx
|
||||
.of(visibleSdks)
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ public class PyConfigurableInterpreterList {
|
||||
private static boolean associatedWithCurrent(Sdk o1, Project project) {
|
||||
final PythonSdkAdditionalData data = (PythonSdkAdditionalData)o1.getSdkAdditionalData();
|
||||
if (data != null) {
|
||||
final String path = data.getAssociatedProjectPath();
|
||||
final String path = data.getAssociatedModulePath();
|
||||
final String projectBasePath = project.getBasePath();
|
||||
if (path != null && path.equals(projectBasePath)) {
|
||||
return true;
|
||||
|
||||
+8
-5
@@ -230,7 +230,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper {
|
||||
Sdk projectSdk = getSdk();
|
||||
final List<Sdk> notAssociatedWithOtherProjects = StreamEx
|
||||
.of(allPythonSdks)
|
||||
.filter(sdk -> !PySdkExtKt.isAssociatedWithAnotherProject(sdk, myProject))
|
||||
.filter(sdk -> !PySdkExtKt.isAssociatedWithAnotherModule(sdk, myModule))
|
||||
.toList();
|
||||
|
||||
final List<Sdk> pythonSdks = myHideOtherProjectVirtualenvs ? notAssociatedWithOtherProjects : allPythonSdks;
|
||||
@@ -256,7 +256,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper {
|
||||
|
||||
private void addSdk(AnActionButton button) {
|
||||
PythonSdkDetailsStep
|
||||
.show(myProject, myProjectSdksModel.getSdks(), null, myMainPanel, button.getPreferredPopupPoint().getScreenPoint(),
|
||||
.show(myProject, myModule, myProjectSdksModel.getSdks(), null, myMainPanel, button.getPreferredPopupPoint().getScreenPoint(),
|
||||
null, sdk -> addCreatedSdk(sdk, true));
|
||||
}
|
||||
|
||||
@@ -339,11 +339,14 @@ public class PythonSdkDetailsDialog extends DialogWrapper {
|
||||
additionalData = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(modificator.getHomePath()));
|
||||
modificator.setSdkAdditionalData(additionalData);
|
||||
}
|
||||
if (isAssociated && myProject != null) {
|
||||
additionalData.associateWithProject(myProject);
|
||||
if (isAssociated && myModule != null) {
|
||||
additionalData.associateWithModule(myModule);
|
||||
}
|
||||
else if (isAssociated && myProject != null) {
|
||||
additionalData.setAssociatedModulePath(myProject.getBasePath());
|
||||
}
|
||||
else {
|
||||
additionalData.setAssociatedProjectPath(null);
|
||||
additionalData.resetAssociatedModulePath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -283,7 +283,7 @@ public class ProjectSpecificSettingsStep<T> extends ProjectSettingsStepBase<T> i
|
||||
|
||||
final String newProjectPath = getNewProjectPath();
|
||||
final PyAddNewEnvironmentPanel newEnvironmentPanel = new PyAddNewEnvironmentPanel(existingSdks, newProjectPath, preferredEnvironment);
|
||||
final PyAddExistingSdkPanel existingSdkPanel = new PyAddExistingSdkPanel(null, existingSdks, newProjectPath, preferredSdk);
|
||||
final PyAddExistingSdkPanel existingSdkPanel = new PyAddExistingSdkPanel(null, null, existingSdks, newProjectPath, preferredSdk);
|
||||
|
||||
final PyAddSdkPanel defaultPanel = PySdkSettings.getInstance().getUseNewEnvironmentForNewProject() ?
|
||||
newEnvironmentPanel : existingSdkPanel;
|
||||
@@ -357,7 +357,7 @@ public class ProjectSpecificSettingsStep<T> extends ProjectSettingsStepBase<T> i
|
||||
final List<Sdk> pythonSdks = PyConfigurableInterpreterList.getInstance(null).getAllPythonSdks();
|
||||
Iterables.removeIf(pythonSdks, sdk -> !(sdk.getSdkType() instanceof PythonSdkType) ||
|
||||
PythonSdkType.isInvalid(sdk) ||
|
||||
PySdkExtKt.getAssociatedProjectPath(sdk) != null);
|
||||
PySdkExtKt.getAssociatedModulePath(sdk) != null);
|
||||
Collections.sort(pythonSdks, new PreferredSdkComparator());
|
||||
return pythonSdks;
|
||||
}
|
||||
|
||||
+3
-1
@@ -3,6 +3,7 @@ package com.jetbrains.python.newProject.steps
|
||||
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
@@ -26,6 +27,7 @@ import java.awt.Component
|
||||
* @author vlan
|
||||
*/
|
||||
class PyAddExistingSdkPanel(project: Project?,
|
||||
module: Module?,
|
||||
existingSdks: List<Sdk>,
|
||||
newProjectPath: String?,
|
||||
preferredSdk: Sdk?) : PyAddSdkPanel() {
|
||||
@@ -55,7 +57,7 @@ class PyAddExistingSdkPanel(project: Project?,
|
||||
|
||||
init {
|
||||
layout = BorderLayout()
|
||||
sdkChooserCombo = PythonSdkChooserCombo(project, existingSdks, newProjectPath, { it != null && it == preferredSdk }).apply {
|
||||
sdkChooserCombo = PythonSdkChooserCombo(project, module, existingSdks, newProjectPath, { it != null && it == preferredSdk }).apply {
|
||||
if (SystemInfo.isMac && !UIUtil.isUnderDarcula()) {
|
||||
putClientProperty("JButton.buttonType", null)
|
||||
}
|
||||
|
||||
+3
-3
@@ -27,9 +27,9 @@ class PyAddNewEnvironmentPanel(existingSdks: List<Sdk>, newProjectPath: String?,
|
||||
}
|
||||
}
|
||||
|
||||
private val panels = listOf(PyAddNewVirtualEnvPanel(null, existingSdks, newProjectPath),
|
||||
PyAddPipEnvPanel(null, existingSdks, newProjectPath),
|
||||
PyAddNewCondaEnvPanel(null, existingSdks, newProjectPath))
|
||||
private val panels = listOf(PyAddNewVirtualEnvPanel(null, null, existingSdks, newProjectPath),
|
||||
PyAddPipEnvPanel(null, null, existingSdks, newProjectPath),
|
||||
PyAddNewCondaEnvPanel(null, null, existingSdks, newProjectPath))
|
||||
|
||||
var selectedPanel: PyAddNewEnvPanel = panels.find { it.envName == preferredType ?: PySdkSettings.instance.preferredEnvironmentType } ?: panels[0]
|
||||
|
||||
|
||||
+1
-3
@@ -75,11 +75,9 @@ public class PythonGenerateProjectCallback<T> extends AbstractNewProjectStep.Abs
|
||||
for (Sdk s : sdks) {
|
||||
final SdkAdditionalData additionalData = s.getSdkAdditionalData();
|
||||
if (additionalData instanceof PythonSdkAdditionalData) {
|
||||
((PythonSdkAdditionalData)additionalData).reassociateWithCreatedProject(newProject);
|
||||
((PythonSdkAdditionalData)additionalData).reAssociateWithCreatedProject(newProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (generator instanceof PythonProjectGenerator) {
|
||||
((PythonProjectGenerator)generator).afterProjectGenerated(newProject);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -16,6 +16,7 @@
|
||||
package com.jetbrains.python.newProject.steps;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
@@ -47,6 +48,7 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PythonSdkChooserCombo(@Nullable final Project project,
|
||||
@Nullable final Module module,
|
||||
@NotNull List<Sdk> sdks,
|
||||
@Nullable String newProjectPath,
|
||||
@NotNull final Condition<Sdk> acceptableSdkCondition) {
|
||||
@@ -58,7 +60,7 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton {
|
||||
comboBox.setRenderer(new PySdkListCellRenderer(null));
|
||||
addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showOptions(project);
|
||||
showOptions(project, module);
|
||||
notifyChanged(e);
|
||||
}
|
||||
});
|
||||
@@ -77,13 +79,13 @@ public class PythonSdkChooserCombo extends ComboboxWithBrowseButton {
|
||||
getComboBox().setToolTipText(item instanceof Sdk ? ((Sdk)item).getHomePath() : null);
|
||||
}
|
||||
|
||||
private void showOptions(@Nullable final Project project) {
|
||||
private void showOptions(@Nullable final Project project, @Nullable Module module) {
|
||||
final PyConfigurableInterpreterList interpreterList = PyConfigurableInterpreterList.getInstance(project);
|
||||
final Sdk[] sdks = interpreterList.getModel().getSdks();
|
||||
//noinspection unchecked
|
||||
final JComboBox<Sdk> comboBox = getComboBox();
|
||||
final Sdk oldSelectedSdk = (Sdk)comboBox.getSelectedItem();
|
||||
PythonSdkDetailsStep.show(project, sdks, null, this, getButton().getLocationOnScreen(), myNewProjectPath, sdk -> {
|
||||
PythonSdkDetailsStep.show(project, module, sdks, null, this, getButton().getLocationOnScreen(), myNewProjectPath, sdk -> {
|
||||
if (sdk == null) return;
|
||||
final ProjectSdksModel projectSdksModel = interpreterList.getModel();
|
||||
if (projectSdksModel.findSdk(sdk) == null) {
|
||||
|
||||
@@ -21,12 +21,14 @@ import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.webcore.packaging.PackagesNotificationPanel
|
||||
import com.jetbrains.python.packaging.ui.PyPackageManagementService
|
||||
@@ -61,11 +63,11 @@ fun detectSystemWideSdks(existingSdks: List<Sdk>): List<PyDetectedSdk> {
|
||||
.toList()
|
||||
}
|
||||
|
||||
fun detectVirtualEnvs(project: Project?, existingSdks: List<Sdk>): List<PyDetectedSdk> =
|
||||
filterSuggestedPaths(VirtualEnvSdkFlavor.INSTANCE.suggestHomePaths(), existingSdks, project)
|
||||
fun detectVirtualEnvs(module: Module?, existingSdks: List<Sdk>): List<PyDetectedSdk> =
|
||||
filterSuggestedPaths(VirtualEnvSdkFlavor.INSTANCE.suggestHomePaths(), existingSdks, module)
|
||||
|
||||
fun detectCondaEnvs(project: Project?, existingSdks: List<Sdk>): List<PyDetectedSdk> =
|
||||
filterSuggestedPaths(CondaEnvSdkFlavor.INSTANCE.suggestHomePaths(), existingSdks, project)
|
||||
fun detectCondaEnvs(module: Module?, existingSdks: List<Sdk>): List<PyDetectedSdk> =
|
||||
filterSuggestedPaths(CondaEnvSdkFlavor.INSTANCE.suggestHomePaths(), existingSdks, module)
|
||||
|
||||
fun createSdkByGenerateTask(generateSdkHomePath: Task.WithResult<String, ExecutionException>,
|
||||
existingSdks: List<Sdk>,
|
||||
@@ -88,30 +90,30 @@ fun createSdkByGenerateTask(generateSdkHomePath: Task.WithResult<String, Executi
|
||||
false, null, suggestedName) ?: return null
|
||||
}
|
||||
|
||||
fun Sdk.associateWithProject(project: Project?, isNewProject: Boolean) {
|
||||
fun Sdk.associateWithModule(module: Module?, isNewProject: Boolean) {
|
||||
getOrCreateAdditionalData().apply {
|
||||
when {
|
||||
isNewProject -> associateWithNewProject()
|
||||
project != null -> associateWithProject(project)
|
||||
module != null -> associateWithModule(module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Sdk.isAssociatedWithProject(project: Project?): Boolean {
|
||||
val basePath = project?.basePath
|
||||
val associatedPath = associatedProjectPath
|
||||
fun Sdk.isAssociatedWithModule(module: Module?): Boolean {
|
||||
val basePath = module?.basePath
|
||||
val associatedPath = associatedModulePath
|
||||
if (basePath != null && associatedPath == basePath) return true
|
||||
if (isAssociatedWithAnotherProject(project)) return false
|
||||
return isLocatedInsideProject(project) || containsProjectName(project)
|
||||
if (isAssociatedWithAnotherModule(module)) return false
|
||||
return isLocatedInsideModule(module) || containsModuleName(module)
|
||||
}
|
||||
|
||||
fun Sdk.isAssociatedWithAnotherProject(project: Project?): Boolean {
|
||||
val basePath = project?.basePath ?: return false
|
||||
val associatedPath = associatedProjectPath ?: return false
|
||||
fun Sdk.isAssociatedWithAnotherModule(module: Module?): Boolean {
|
||||
val basePath = module?.basePath ?: return false
|
||||
val associatedPath = associatedModulePath ?: return false
|
||||
return basePath != associatedPath
|
||||
}
|
||||
|
||||
val Sdk.associatedProjectPath: String?
|
||||
val Sdk.associatedModulePath: String?
|
||||
// TODO: Support .project associations
|
||||
get() = associatedPathFromAdditionalData /*?: associatedPathFromDotProject*/
|
||||
|
||||
@@ -125,9 +127,9 @@ fun PyDetectedSdk.setup(existingSdks: List<Sdk>): Sdk? {
|
||||
return SdkConfigurationUtil.setupSdk(existingSdks.toTypedArray(), homeDir, PythonSdkType.getInstance(), false, null, null)
|
||||
}
|
||||
|
||||
fun PyDetectedSdk.setupAssociated(existingSdks: List<Sdk>, associatedProjectPath: String?): Sdk? {
|
||||
fun PyDetectedSdk.setupAssociated(existingSdks: List<Sdk>, associatedModulePath: String?): Sdk? {
|
||||
val homeDir = homeDirectory ?: return null
|
||||
val suggestedName = homePath?.let { suggestAssociatedSdkName(it, associatedProjectPath) }
|
||||
val suggestedName = homePath?.let { suggestAssociatedSdkName(it, associatedModulePath) }
|
||||
return SdkConfigurationUtil.setupSdk(existingSdks.toTypedArray(), homeDir, PythonSdkType.getInstance(), false, null, suggestedName)
|
||||
}
|
||||
|
||||
@@ -149,6 +151,13 @@ var Project.pythonSdk: Sdk?
|
||||
}
|
||||
}
|
||||
|
||||
val Module.baseDir: VirtualFile?
|
||||
get() = rootManager.contentRoots.firstOrNull()
|
||||
|
||||
val Module.basePath: String?
|
||||
get() = baseDir?.path
|
||||
|
||||
|
||||
private fun suggestAssociatedSdkName(sdkHome: String, associatedPath: String?): String? {
|
||||
val baseSdkName = PythonSdkType.suggestBaseSdkName(sdkHome) ?: return null
|
||||
val venvRoot = PythonSdkType.getVirtualEnvRoot(sdkHome)?.path
|
||||
@@ -186,11 +195,11 @@ private val Sdk.associatedPathFromDotProject: String?
|
||||
}
|
||||
|
||||
private val Sdk.associatedPathFromAdditionalData: String?
|
||||
get() = (sdkAdditionalData as? PythonSdkAdditionalData)?.associatedProjectPath
|
||||
get() = (sdkAdditionalData as? PythonSdkAdditionalData)?.associatedModulePath
|
||||
|
||||
private fun Sdk.isLocatedInsideProject(project: Project?): Boolean {
|
||||
private fun Sdk.isLocatedInsideModule(module: Module?): Boolean {
|
||||
val homePath = homePath ?: return false
|
||||
val basePath = project?.basePath ?: return false
|
||||
val basePath = module?.basePath ?: return false
|
||||
return FileUtil.isAncestor(basePath, homePath, true)
|
||||
}
|
||||
|
||||
@@ -202,9 +211,9 @@ private val PyDetectedSdk.guessedLanguageLevel: LanguageLevel?
|
||||
return LanguageLevel.fromPythonVersion(versionString)
|
||||
}
|
||||
|
||||
private fun Sdk.containsProjectName(project: Project?): Boolean {
|
||||
private fun Sdk.containsModuleName(module: Module?): Boolean {
|
||||
val path = homePath ?: return false
|
||||
val name = project?.name ?: return false
|
||||
val name = module?.name ?: return false
|
||||
return path.contains(name, true)
|
||||
}
|
||||
|
||||
@@ -220,14 +229,14 @@ fun Sdk.getOrCreateAdditionalData(): PythonSdkAdditionalData {
|
||||
|
||||
private fun filterSuggestedPaths(suggestedPaths: MutableCollection<String>,
|
||||
existingSdks: List<Sdk>,
|
||||
project: Project?): List<PyDetectedSdk> {
|
||||
module: Module?): List<PyDetectedSdk> {
|
||||
val existingPaths = existingSdks.map { it.homePath }.toSet()
|
||||
return suggestedPaths
|
||||
.asSequence()
|
||||
.filterNot { it in existingPaths }
|
||||
.distinct()
|
||||
.map { PyDetectedSdk(it) }
|
||||
.sortedWith(compareBy<PyDetectedSdk>({ it.isAssociatedWithProject(project) },
|
||||
.sortedWith(compareBy<PyDetectedSdk>({ it.isAssociatedWithModule(module) },
|
||||
{ it.homePath }).reversed())
|
||||
.toList()
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.jetbrains.python.sdk;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.SdkAdditionalData;
|
||||
@@ -53,7 +54,7 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
|
||||
private final VirtualFilePointerContainer myExcludedPaths;
|
||||
|
||||
private final PythonSdkFlavor myFlavor;
|
||||
private String myAssociatedProjectPath;
|
||||
private String myAssociatedModulePath;
|
||||
private boolean myAssociateWithNewProject;
|
||||
private boolean myIsPipEnv;
|
||||
|
||||
@@ -87,19 +88,23 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
|
||||
}
|
||||
}
|
||||
|
||||
public String getAssociatedProjectPath() {
|
||||
return myAssociatedProjectPath;
|
||||
public String getAssociatedModulePath() {
|
||||
return myAssociatedModulePath;
|
||||
}
|
||||
|
||||
public void setAssociatedProjectPath(@Nullable String associatedProjectPath) {
|
||||
myAssociatedProjectPath = associatedProjectPath;
|
||||
public void resetAssociatedModulePath() {
|
||||
setAssociatedModulePath(null);
|
||||
}
|
||||
|
||||
public void setAssociatedModulePath(@Nullable String associatedModulePath) {
|
||||
myAssociatedModulePath = associatedModulePath;
|
||||
myAssociateWithNewProject = false;
|
||||
}
|
||||
|
||||
public void associateWithProject(@NotNull Project project) {
|
||||
final String path = project.getBasePath();
|
||||
public void associateWithModule(@NotNull Module module) {
|
||||
final String path = PySdkExtKt.getBasePath(module);
|
||||
if (path != null) {
|
||||
myAssociatedProjectPath = FileUtil.toSystemIndependentName(path);
|
||||
myAssociatedModulePath = FileUtil.toSystemIndependentName(path);
|
||||
}
|
||||
myAssociateWithNewProject = false;
|
||||
}
|
||||
@@ -108,9 +113,9 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
|
||||
myAssociateWithNewProject = true;
|
||||
}
|
||||
|
||||
public void reassociateWithCreatedProject(@NotNull Project project) {
|
||||
public void reAssociateWithCreatedProject(@NotNull Project project) {
|
||||
if (myAssociateWithNewProject) {
|
||||
associateWithProject(project);
|
||||
setAssociatedModulePath(project.getBasePath());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +131,8 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
|
||||
savePaths(rootElement, myAddedPaths, PATHS_ADDED_BY_USER_ROOT, PATH_ADDED_BY_USER);
|
||||
savePaths(rootElement, myExcludedPaths, PATHS_REMOVED_BY_USER_ROOT, PATH_REMOVED_BY_USER);
|
||||
|
||||
if (myAssociatedProjectPath != null) {
|
||||
rootElement.setAttribute(ASSOCIATED_PROJECT_PATH, myAssociatedProjectPath);
|
||||
if (myAssociatedModulePath != null) {
|
||||
rootElement.setAttribute(ASSOCIATED_PROJECT_PATH, myAssociatedModulePath);
|
||||
// XXX: We have to persist the pipenv flag since pipenv is no different from a regular
|
||||
// virtualenv and currently we want to handle pipenvs differently. Consider adding an SDK
|
||||
// extension mechanism for that
|
||||
@@ -163,7 +168,7 @@ public class PythonSdkAdditionalData implements SdkAdditionalData {
|
||||
collectPaths(JDOMExternalizer.loadStringsList(element, PATHS_ADDED_BY_USER_ROOT, PATH_ADDED_BY_USER),myAddedPaths);
|
||||
collectPaths(JDOMExternalizer.loadStringsList(element, PATHS_REMOVED_BY_USER_ROOT, PATH_REMOVED_BY_USER),myExcludedPaths);
|
||||
if (element != null) {
|
||||
data.setAssociatedProjectPath(element.getAttributeValue(ASSOCIATED_PROJECT_PATH));
|
||||
data.setAssociatedModulePath(element.getAttributeValue(ASSOCIATED_PROJECT_PATH));
|
||||
data.setPipEnv("true".equals(element.getAttributeValue(IS_PIPENV)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.jetbrains.python.sdk;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
@@ -38,7 +39,8 @@ import java.util.List;
|
||||
|
||||
public class PythonSdkDetailsStep extends BaseListPopupStep<String> {
|
||||
@Nullable private final DialogWrapper myShowAll;
|
||||
private final Project myProject;
|
||||
@Nullable private final Project myProject;
|
||||
@Nullable private final Module myModule;
|
||||
private final Sdk[] myExistingSdks;
|
||||
private final NullableConsumer<Sdk> mySdkAddedCallback;
|
||||
|
||||
@@ -47,13 +49,14 @@ public class PythonSdkDetailsStep extends BaseListPopupStep<String> {
|
||||
@Nullable private String myNewProjectPath;
|
||||
|
||||
public static void show(@Nullable final Project project,
|
||||
@Nullable final Module module,
|
||||
@NotNull final Sdk[] existingSdks,
|
||||
@Nullable final DialogWrapper showAllDialog,
|
||||
@NotNull JComponent ownerComponent,
|
||||
@NotNull final Point popupPoint,
|
||||
@Nullable String newProjectPath,
|
||||
@NotNull final NullableConsumer<Sdk> sdkAddedCallback) {
|
||||
final PythonSdkDetailsStep sdkHomesStep = new PythonSdkDetailsStep(project, showAllDialog, existingSdks, sdkAddedCallback);
|
||||
final PythonSdkDetailsStep sdkHomesStep = new PythonSdkDetailsStep(project, module, showAllDialog, existingSdks, sdkAddedCallback);
|
||||
if (showAllDialog == null) {
|
||||
sdkHomesStep.createLocalSdk();
|
||||
}
|
||||
@@ -65,11 +68,13 @@ public class PythonSdkDetailsStep extends BaseListPopupStep<String> {
|
||||
}
|
||||
|
||||
public PythonSdkDetailsStep(@Nullable final Project project,
|
||||
@Nullable final Module module,
|
||||
@Nullable final DialogWrapper showAllDialog,
|
||||
@NotNull final Sdk[] existingSdks,
|
||||
@NotNull final NullableConsumer<Sdk> sdkAddedCallback) {
|
||||
super(null, getAvailableOptions(showAllDialog != null));
|
||||
myProject = project;
|
||||
myModule = module;
|
||||
myShowAll = showAllDialog;
|
||||
myExistingSdks = existingSdks;
|
||||
mySdkAddedCallback = sdkAddedCallback;
|
||||
@@ -103,7 +108,7 @@ public class PythonSdkDetailsStep extends BaseListPopupStep<String> {
|
||||
|
||||
private void createLocalSdk() {
|
||||
final Project project = myNewProjectPath != null ? null : myProject;
|
||||
final PyAddSdkDialog dialog = PyAddSdkDialog.create(project, Arrays.asList(myExistingSdks), myNewProjectPath);
|
||||
final PyAddSdkDialog dialog = PyAddSdkDialog.create(project, myModule, Arrays.asList(myExistingSdks), myNewProjectPath);
|
||||
final Sdk sdk = dialog.showAndGet() ? dialog.getOrCreateSdk() : null;
|
||||
mySdkAddedCallback.consume(sdk);
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ public final class PythonSdkType extends SdkType {
|
||||
if (pointerInfo == null) return;
|
||||
final Point point = pointerInfo.getLocation();
|
||||
PythonSdkDetailsStep
|
||||
.show(project, sdkModel.getSdks(), null, parentComponent, point, null, sdk -> {
|
||||
.show(project, null, sdkModel.getSdks(), null, parentComponent, point, null, sdk -> {
|
||||
if (sdk != null) {
|
||||
sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference<>(parentComponent));
|
||||
sdkCreatedCallback.consume(sdk);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.jetbrains.python.sdk.add
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.ValidationInfo
|
||||
@@ -29,12 +30,13 @@ import javax.swing.Icon
|
||||
* @author vlan
|
||||
*/
|
||||
class PyAddExistingCondaEnvPanel(private val project: Project?,
|
||||
private val module: Module?,
|
||||
private val existingSdks: List<Sdk>,
|
||||
override var newProjectPath: String?) : PyAddSdkPanel() {
|
||||
override val panelName: String = "Existing environment"
|
||||
override val icon: Icon = PythonIcons.Python.Condaenv
|
||||
private val sdkComboBox = PySdkPathChoosingComboBox(detectCondaEnvs(project, existingSdks)
|
||||
.filterNot { it.isAssociatedWithAnotherProject(project) },
|
||||
private val sdkComboBox = PySdkPathChoosingComboBox(detectCondaEnvs(module, existingSdks)
|
||||
.filterNot { it.isAssociatedWithAnotherModule(module) },
|
||||
null)
|
||||
private val makeSharedField = JBCheckBox("Make available to all projects")
|
||||
|
||||
@@ -54,7 +56,7 @@ class PyAddExistingCondaEnvPanel(private val project: Project?,
|
||||
return when (sdk) {
|
||||
is PyDetectedSdk -> sdk.setupAssociated(existingSdks, newProjectPath ?: project?.basePath)?.apply {
|
||||
if (!makeSharedField.isSelected) {
|
||||
associateWithProject(project, newProjectPath != null)
|
||||
associateWithModule(module, newProjectPath != null)
|
||||
}
|
||||
}
|
||||
else -> sdk
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.jetbrains.python.sdk.add
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.ValidationInfo
|
||||
@@ -29,12 +30,13 @@ import javax.swing.Icon
|
||||
* @author vlan
|
||||
*/
|
||||
class PyAddExistingVirtualEnvPanel(private val project: Project?,
|
||||
private val module: Module?,
|
||||
private val existingSdks: List<Sdk>,
|
||||
override var newProjectPath: String?) : PyAddSdkPanel() {
|
||||
override val panelName: String = "Existing environment"
|
||||
override val icon: Icon = PythonIcons.Python.Virtualenv
|
||||
private val sdkComboBox = PySdkPathChoosingComboBox(detectVirtualEnvs(project, existingSdks)
|
||||
.filterNot { it.isAssociatedWithAnotherProject(project) },
|
||||
private val sdkComboBox = PySdkPathChoosingComboBox(detectVirtualEnvs(module, existingSdks)
|
||||
.filterNot { it.isAssociatedWithAnotherModule(module) },
|
||||
null)
|
||||
private val makeSharedField = JBCheckBox("Make available to all projects")
|
||||
|
||||
@@ -56,7 +58,7 @@ class PyAddExistingVirtualEnvPanel(private val project: Project?,
|
||||
return when (sdk) {
|
||||
is PyDetectedSdk -> sdk.setupAssociated(existingSdks, newProjectPath ?: project?.basePath)?.apply {
|
||||
if (!makeSharedField.isSelected) {
|
||||
associateWithProject(project, newProjectPath != null)
|
||||
associateWithModule(module, newProjectPath != null)
|
||||
}
|
||||
}
|
||||
else -> sdk
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.jetbrains.python.sdk.add
|
||||
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -34,7 +35,8 @@ import com.intellij.util.ui.FormBuilder
|
||||
import com.jetbrains.python.packaging.PyCondaPackageManagerImpl
|
||||
import com.jetbrains.python.packaging.PyCondaPackageService
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import com.jetbrains.python.sdk.associateWithProject
|
||||
import com.jetbrains.python.sdk.associateWithModule
|
||||
import com.jetbrains.python.sdk.basePath
|
||||
import com.jetbrains.python.sdk.createSdkByGenerateTask
|
||||
import icons.PythonIcons
|
||||
import org.jetbrains.annotations.SystemIndependent
|
||||
@@ -49,6 +51,7 @@ import javax.swing.event.DocumentEvent
|
||||
* @author vlan
|
||||
*/
|
||||
class PyAddNewCondaEnvPanel(private val project: Project?,
|
||||
private val module: Module?,
|
||||
private val existingSdks: List<Sdk>,
|
||||
newProjectPath: String?) : PyAddNewEnvPanel() {
|
||||
override val envName: String = "Conda"
|
||||
@@ -117,10 +120,10 @@ class PyAddNewCondaEnvPanel(private val project: Project?,
|
||||
}
|
||||
}
|
||||
val shared = makeSharedField.isSelected
|
||||
val associatedPath = if (!shared) newProjectPath ?: project?.basePath else null
|
||||
val associatedPath = if (!shared) projectBasePath else null
|
||||
val sdk = createSdkByGenerateTask(task, existingSdks, null, associatedPath, null) ?: return null
|
||||
if (!shared) {
|
||||
sdk.associateWithProject(project, newProjectPath != null)
|
||||
sdk.associateWithModule(module, newProjectPath != null)
|
||||
}
|
||||
PyCondaPackageService.getInstance().PREFERRED_CONDA_PATH = condaPath
|
||||
return sdk
|
||||
@@ -162,7 +165,7 @@ class PyAddNewCondaEnvPanel(private val project: Project?,
|
||||
}
|
||||
|
||||
private val projectBasePath: @SystemIndependent String?
|
||||
get() = newProjectPath ?: project?.basePath
|
||||
get() = newProjectPath ?: module?.basePath ?: project?.basePath
|
||||
|
||||
private val selectedLanguageLevel: String
|
||||
get() = languageLevelsField.getItemAt(languageLevelsField.selectedIndex)
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jetbrains.python.sdk.add
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtil
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task
|
||||
@@ -46,6 +47,7 @@ import javax.swing.event.DocumentEvent
|
||||
* @author vlan
|
||||
*/
|
||||
class PyAddNewVirtualEnvPanel(private val project: Project?,
|
||||
private val module: Module?,
|
||||
private val existingSdks: List<Sdk>,
|
||||
newProjectPath: String?) : PyAddNewEnvPanel() {
|
||||
override val envName: String = "Virtualenv"
|
||||
@@ -106,10 +108,10 @@ class PyAddNewVirtualEnvPanel(private val project: Project?,
|
||||
}
|
||||
}
|
||||
val shared = makeSharedField.isSelected
|
||||
val associatedPath = if (!shared) newProjectPath ?: project?.basePath else null
|
||||
val associatedPath = if (!shared) projectBasePath else null
|
||||
val sdk = createSdkByGenerateTask(task, existingSdks, baseSdkField.selectedSdk, associatedPath, null) ?: return null
|
||||
if (!shared) {
|
||||
sdk.associateWithProject(project, newProjectPath != null)
|
||||
sdk.associateWithModule(module, newProjectPath != null)
|
||||
}
|
||||
excludeDirectoryFromProject(root, project)
|
||||
with(PySdkSettings.instance) {
|
||||
@@ -148,7 +150,7 @@ class PyAddNewVirtualEnvPanel(private val project: Project?,
|
||||
}
|
||||
|
||||
private val projectBasePath: @SystemIndependent String
|
||||
get() = newProjectPath ?: project?.basePath ?: userHome
|
||||
get() = newProjectPath ?: module?.basePath ?: project?.basePath ?: userHome
|
||||
|
||||
private val userHome: @SystemIndependent String
|
||||
get() = FileUtil.toSystemIndependentName(SystemProperties.getUserHome())
|
||||
|
||||
@@ -1,45 +1,63 @@
|
||||
// Copyright 2000-2018 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.add
|
||||
|
||||
import com.intellij.application.options.ModuleListCellRenderer
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.ComboBox
|
||||
import com.intellij.openapi.ui.ValidationInfo
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.util.PlatformUtils
|
||||
import com.intellij.util.ui.FormBuilder
|
||||
import com.jetbrains.python.PythonModuleTypeBase
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import com.jetbrains.python.sdk.associatedProjectPath
|
||||
import com.jetbrains.python.sdk.associatedModulePath
|
||||
import com.jetbrains.python.sdk.basePath
|
||||
import com.jetbrains.python.sdk.flavors.*
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import java.awt.event.ItemEvent
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JComboBox
|
||||
|
||||
/**
|
||||
* The UI panel for adding the pipenv interpreter for the project.
|
||||
*
|
||||
* TODO: Pass a module here, since pipenv interpreters are per module, not per project.
|
||||
*
|
||||
* @author vlan
|
||||
*/
|
||||
class PyAddPipEnvPanel(private val project: Project?,
|
||||
private val module: Module?,
|
||||
private val existingSdks: List<Sdk>,
|
||||
override var newProjectPath: String?) : PyAddNewEnvPanel() {
|
||||
override val envName = "Pipenv"
|
||||
override val panelName = "Pipenv Environment"
|
||||
override val icon: Icon = PIPENV_ICON
|
||||
|
||||
private val DEFAULT_PYTHON = "Default"
|
||||
private val DEFAULT_PYTHON = "<Default>"
|
||||
private val moduleField: JComboBox<Module>
|
||||
private val languageLevelsField: JComboBox<String>
|
||||
private val installPackagesCheckBox = JBCheckBox("Install packages from Pipfile").apply {
|
||||
isEnabled = projectPipFile != null
|
||||
isVisible = newProjectPath != null
|
||||
isVisible = newProjectPath == null
|
||||
}
|
||||
|
||||
init {
|
||||
layout = BorderLayout()
|
||||
|
||||
val modules = project?.let {
|
||||
ModuleUtil.getModulesOfType(it, PythonModuleTypeBase.getInstance())
|
||||
} ?: emptyList()
|
||||
|
||||
moduleField = JComboBox(modules.toTypedArray()).apply {
|
||||
renderer = ModuleListCellRenderer()
|
||||
preferredSize = Dimension(Int.MAX_VALUE, preferredSize.height)
|
||||
addItemListener {
|
||||
if (it.stateChange == ItemEvent.SELECTED) {
|
||||
updateInstallPackagesCheckBox()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val supportedLanguageLevels =
|
||||
listOf(DEFAULT_PYTHON,
|
||||
LanguageLevel.PYTHON37,
|
||||
@@ -49,26 +67,39 @@ class PyAddPipEnvPanel(private val project: Project?,
|
||||
LanguageLevel.PYTHON27)
|
||||
.map { it.toString() }
|
||||
|
||||
languageLevelsField = ComboBox(supportedLanguageLevels.toTypedArray()).apply {
|
||||
languageLevelsField = JComboBox(supportedLanguageLevels.toTypedArray()).apply {
|
||||
selectedItem = if (itemCount > 0) getItemAt(0) else null
|
||||
}
|
||||
|
||||
val formPanel = FormBuilder.createFormBuilder()
|
||||
.addLabeledComponent("Python version:", languageLevelsField)
|
||||
.addComponent(installPackagesCheckBox)
|
||||
.panel
|
||||
add(formPanel, BorderLayout.NORTH)
|
||||
val builder = FormBuilder.createFormBuilder().apply {
|
||||
if (module == null && modules.size > 1) {
|
||||
val associatedObject = if (PlatformUtils.isPyCharm()) "project" else "module"
|
||||
addLabeledComponent("Associated $associatedObject:", moduleField)
|
||||
}
|
||||
addLabeledComponent("Python version:", languageLevelsField)
|
||||
addComponent(installPackagesCheckBox)
|
||||
}
|
||||
add(builder.panel, BorderLayout.NORTH)
|
||||
updateInstallPackagesCheckBox()
|
||||
}
|
||||
|
||||
override fun getOrCreateSdk(): Sdk? {
|
||||
// TODO: Pass a module here for selecting the proper Pipfile
|
||||
return setupPipEnvSdkUnderProgress(project, null, existingSdks, newProjectPath,
|
||||
return setupPipEnvSdkUnderProgress(project, selectedModule, existingSdks, newProjectPath,
|
||||
selectedLanguageLevel, installPackagesCheckBox.isSelected)
|
||||
}
|
||||
|
||||
override fun validateAll(): List<ValidationInfo> =
|
||||
listOfNotNull(validatePipEnvExecutable(), validatePipEnvIsNotAdded())
|
||||
|
||||
private fun updateInstallPackagesCheckBox() {
|
||||
selectedModule?.let {
|
||||
installPackagesCheckBox.isEnabled = it.pipFiles.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
private val selectedModule: Module?
|
||||
get() = module ?: moduleField.selectedItem as? Module
|
||||
|
||||
/**
|
||||
* Checks if `pipenv` is available on `$PATH`.
|
||||
*/
|
||||
@@ -84,7 +115,7 @@ class PyAddPipEnvPanel(private val project: Project?,
|
||||
private fun validatePipEnvIsNotAdded(): ValidationInfo? {
|
||||
val path = projectPath ?: return null
|
||||
val addedPipEnv = existingSdks.find {
|
||||
it.associatedProjectPath == path && it.isPipEnv
|
||||
it.associatedModulePath == path && it.isPipEnv
|
||||
} ?: return null
|
||||
return ValidationInfo("""Pipenv interpreter has been already added, select "${addedPipEnv.name}" in your interpreters list""")
|
||||
}
|
||||
@@ -93,7 +124,7 @@ class PyAddPipEnvPanel(private val project: Project?,
|
||||
* The effective project path for the new project or for the existing project.
|
||||
*/
|
||||
private val projectPath: String?
|
||||
get() = newProjectPath ?: project?.basePath
|
||||
get() = newProjectPath ?: selectedModule?.basePath ?: project?.basePath
|
||||
|
||||
/**
|
||||
* The version of Python selected by the user or `null` if the default version is selected.
|
||||
@@ -103,13 +134,4 @@ class PyAddPipEnvPanel(private val project: Project?,
|
||||
val text = languageLevelsField.getItemAt(languageLevelsField.selectedIndex)
|
||||
return if (text == DEFAULT_PYTHON) null else text
|
||||
}
|
||||
|
||||
/**
|
||||
* The Pipfile for the effective project path.
|
||||
*/
|
||||
private val projectPipFile: VirtualFile?
|
||||
get() {
|
||||
val path = projectPath ?: return null
|
||||
return StandardFileSystems.local().findFileByPath(path)?.findChild(PIP_FILE)
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.jetbrains.python.sdk.add
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
@@ -37,7 +38,7 @@ import com.jetbrains.python.sdk.PythonSdkType
|
||||
import com.jetbrains.python.sdk.add.PyAddSdkDialog.Companion.create
|
||||
import com.jetbrains.python.sdk.add.PyAddSdkDialogFlowAction.*
|
||||
import com.jetbrains.python.sdk.detectVirtualEnvs
|
||||
import com.jetbrains.python.sdk.isAssociatedWithProject
|
||||
import com.jetbrains.python.sdk.isAssociatedWithModule
|
||||
import icons.PythonIcons
|
||||
import java.awt.CardLayout
|
||||
import java.awt.event.ActionEvent
|
||||
@@ -54,6 +55,7 @@ import javax.swing.JPanel
|
||||
* @author vlan
|
||||
*/
|
||||
class PyAddSdkDialog private constructor(private val project: Project?,
|
||||
private val module: Module?,
|
||||
private val existingSdks: List<Sdk>,
|
||||
private val newProjectPath: String?) : DialogWrapper(project) {
|
||||
/**
|
||||
@@ -72,12 +74,15 @@ class PyAddSdkDialog private constructor(private val project: Project?,
|
||||
val sdks = existingSdks
|
||||
.filter { it.sdkType is PythonSdkType && !PythonSdkType.isInvalid(it) }
|
||||
.sortedWith(PreferredSdkComparator())
|
||||
val panels = arrayListOf<PyAddSdkView>(createVirtualEnvPanel(project, sdks, newProjectPath),
|
||||
val panels = arrayListOf<PyAddSdkView>(createVirtualEnvPanel(project, module, sdks, newProjectPath),
|
||||
createPipEnvPanel(),
|
||||
createAnacondaPanel(project),
|
||||
createAnacondaPanel(project, module),
|
||||
PyAddSystemWideInterpreterPanel(existingSdks))
|
||||
val extendedPanels = PyAddSdkProvider.EP_NAME.extensions
|
||||
.mapNotNull { it.createView(project = project, newProjectPath = newProjectPath, existingSdks = existingSdks).registerIfDisposable() }
|
||||
.mapNotNull {
|
||||
it.createView(project = project, module = module, newProjectPath = newProjectPath, existingSdks = existingSdks)
|
||||
.registerIfDisposable()
|
||||
}
|
||||
panels.addAll(extendedPanels)
|
||||
mainPanel.add(SPLITTER_COMPONENT_CARD_PANE, createCardSplitter(panels))
|
||||
return mainPanel
|
||||
@@ -202,37 +207,38 @@ class PyAddSdkDialog private constructor(private val project: Project?,
|
||||
}
|
||||
|
||||
private fun createVirtualEnvPanel(project: Project?,
|
||||
module: Module?,
|
||||
existingSdks: List<Sdk>,
|
||||
newProjectPath: String?): PyAddSdkPanel {
|
||||
val newVirtualEnvPanel = when {
|
||||
allowCreatingNewEnvironments(project) -> PyAddNewVirtualEnvPanel(project, existingSdks, newProjectPath)
|
||||
allowCreatingNewEnvironments(project) -> PyAddNewVirtualEnvPanel(project, module, existingSdks, newProjectPath)
|
||||
else -> null
|
||||
}
|
||||
val existingVirtualEnvPanel = PyAddExistingVirtualEnvPanel(project, existingSdks, newProjectPath)
|
||||
val existingVirtualEnvPanel = PyAddExistingVirtualEnvPanel(project, module, existingSdks, newProjectPath)
|
||||
val panels = listOf(newVirtualEnvPanel,
|
||||
existingVirtualEnvPanel)
|
||||
.filterNotNull()
|
||||
val defaultPanel = when {
|
||||
detectVirtualEnvs(project, existingSdks).any { it.isAssociatedWithProject(project) } -> existingVirtualEnvPanel
|
||||
detectVirtualEnvs(module, existingSdks).any { it.isAssociatedWithModule(module) } -> existingVirtualEnvPanel
|
||||
newVirtualEnvPanel != null -> newVirtualEnvPanel
|
||||
else -> existingVirtualEnvPanel
|
||||
}
|
||||
return PyAddSdkGroupPanel("Virtualenv environment", PythonIcons.Python.Virtualenv, panels, defaultPanel)
|
||||
}
|
||||
|
||||
private fun createAnacondaPanel(project: Project?): PyAddSdkPanel {
|
||||
private fun createAnacondaPanel(project: Project?, module: Module?): PyAddSdkPanel {
|
||||
val newCondaEnvPanel = when {
|
||||
allowCreatingNewEnvironments(project) -> PyAddNewCondaEnvPanel(project, existingSdks, newProjectPath)
|
||||
allowCreatingNewEnvironments(project) -> PyAddNewCondaEnvPanel(project, module, existingSdks, newProjectPath)
|
||||
else -> null
|
||||
}
|
||||
val panels = listOf(newCondaEnvPanel,
|
||||
PyAddExistingCondaEnvPanel(project, existingSdks, newProjectPath))
|
||||
PyAddExistingCondaEnvPanel(project, module, existingSdks, newProjectPath))
|
||||
.filterNotNull()
|
||||
return PyAddSdkGroupPanel("Conda environment", PythonIcons.Python.Anaconda, panels, panels[0])
|
||||
}
|
||||
|
||||
private fun createPipEnvPanel(): PyAddSdkPanel {
|
||||
return PyAddPipEnvPanel(project, existingSdks, newProjectPath)
|
||||
return PyAddPipEnvPanel(project, module, existingSdks, newProjectPath)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,8 +333,10 @@ class PyAddSdkDialog private constructor(private val project: Project?,
|
||||
private const val WIZARD_CARD_PANE = "Wizard"
|
||||
|
||||
@JvmStatic
|
||||
fun create(project: Project?, existingSdks: List<Sdk>, newProjectPath: String?): PyAddSdkDialog {
|
||||
return PyAddSdkDialog(project = project, existingSdks = existingSdks, newProjectPath = newProjectPath).apply { init() }
|
||||
fun create(project: Project?, module: Module?, existingSdks: List<Sdk>, newProjectPath: String?): PyAddSdkDialog {
|
||||
return PyAddSdkDialog(project = project, module = module, existingSdks = existingSdks, newProjectPath = newProjectPath).apply {
|
||||
init()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.jetbrains.python.sdk.add
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
|
||||
@@ -9,7 +10,7 @@ interface PyAddSdkProvider {
|
||||
/**
|
||||
* Returns [PyAddSdkView] if applicable.
|
||||
*/
|
||||
fun createView(project: Project?, newProjectPath: String?, existingSdks: List<Sdk>): PyAddSdkView?
|
||||
fun createView(project: Project?, module: Module?, newProjectPath: String?, existingSdks: List<Sdk>): PyAddSdkView?
|
||||
|
||||
companion object {
|
||||
val EP_NAME: ExtensionPointName<PyAddSdkProvider> = ExtensionPointName.create("Pythonid.pyAddSdkProvider")
|
||||
|
||||
@@ -17,6 +17,8 @@ package com.jetbrains.python.sdk.flavors;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -24,6 +26,8 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.jetbrains.python.PythonModuleTypeBase;
|
||||
import com.jetbrains.python.sdk.PySdkExtKt;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import icons.PythonIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -50,9 +54,12 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor {
|
||||
final Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
|
||||
List<String> candidates = new ArrayList<>();
|
||||
if (project != null) {
|
||||
VirtualFile rootDir = project.getBaseDir();
|
||||
if (rootDir != null)
|
||||
candidates.addAll(findInDirectory(rootDir));
|
||||
for (Module module : ModuleUtil.getModulesOfType(project, PythonModuleTypeBase.getInstance())) {
|
||||
final VirtualFile baseDir = PySdkExtKt.getBaseDir(module);
|
||||
if (baseDir != null) {
|
||||
candidates.addAll(findInDirectory(baseDir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final VirtualFile path = getDefaultLocation();
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.jetbrains.python.packaging.PyExecutionException
|
||||
import com.jetbrains.python.sdk.*
|
||||
import icons.PythonIcons
|
||||
import org.jetbrains.annotations.SystemDependent
|
||||
import org.jetbrains.jps.model.serialization.PathMacroUtil
|
||||
import java.io.File
|
||||
import javax.swing.Icon
|
||||
|
||||
@@ -94,7 +93,7 @@ fun setupPipEnvSdkUnderProgress(project: Project?,
|
||||
val suggestedName = "Pipenv (${PathUtil.getFileName(projectPath)})"
|
||||
return createSdkByGenerateTask(task, existingSdks, null, projectPath, suggestedName)?.apply {
|
||||
isPipEnv = true
|
||||
associateWithProject(project, newProjectPath != null)
|
||||
associateWithModule(module, newProjectPath != null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,9 +192,3 @@ class UsePipEnvQuickFix : LocalQuickFix {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory with the module file taking into account .idea/.
|
||||
*/
|
||||
private val Module.basePath: String?
|
||||
get() = PathMacroUtil.getModuleDir(moduleFilePath)
|
||||
|
||||
Reference in New Issue
Block a user