diff --git a/plugins/ide-features-trainer/src/training/lang/AbstractLangSupport.kt b/plugins/ide-features-trainer/src/training/lang/AbstractLangSupport.kt
index 278435807ca0..4a5ced5aa99e 100644
--- a/plugins/ide-features-trainer/src/training/lang/AbstractLangSupport.kt
+++ b/plugins/ide-features-trainer/src/training/lang/AbstractLangSupport.kt
@@ -1,6 +1,7 @@
// 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 training.lang
+import com.intellij.ide.impl.OpenProjectTask
import com.intellij.ide.impl.ProjectUtil
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
@@ -25,7 +26,9 @@ abstract class AbstractLangSupport : LangSupport {
override fun installAndOpenLearningProject(projectPath: Path,
projectToClose: Project?,
postInitCallback: (learnProject: Project) -> Unit) {
- ProjectUtils.simpleInstallAndOpenLearningProject(projectPath, projectToClose, this, postInitCallback)
+ ProjectUtils.simpleInstallAndOpenLearningProject(projectPath, this,
+ OpenProjectTask(projectToClose = projectToClose),
+ postInitCallback)
}
override fun getSdkForProject(project: Project): Sdk? {
diff --git a/plugins/ide-features-trainer/src/training/learn/OpenLessonActivities.kt b/plugins/ide-features-trainer/src/training/learn/OpenLessonActivities.kt
index 0173ee1ec450..e6c559d3a9d4 100644
--- a/plugins/ide-features-trainer/src/training/learn/OpenLessonActivities.kt
+++ b/plugins/ide-features-trainer/src/training/learn/OpenLessonActivities.kt
@@ -173,7 +173,9 @@ internal object OpenLessonActivities {
//open next lesson if current is passed
LOG.debug("${project.name}: Set lesson view")
- LearningUiManager.activeToolWindow?.setLearnPanel()
+ LearningUiManager.activeToolWindow = LearnToolWindowFactory.learnWindowPerProject[project]?.also {
+ it.setLearnPanel()
+ }
LOG.debug("${project.name}: XmlLesson onStart()")
lesson.onStart()
@@ -269,9 +271,9 @@ internal object OpenLessonActivities {
val learnToolWindow = toolWindowManager.getToolWindow(LearnToolWindowFactory.LEARN_TOOL_WINDOW)
if (learnToolWindow != null) {
val runnable = if (lesson.properties.showLearnToolwindowAtStart) null else Runnable { learnToolWindow.hide() }
- learnToolWindow.show(runnable)
DumbService.getInstance(myLearnProject).runWhenSmart {
- // Try to fix PyChar double startup indexing :(
+ learnToolWindow.show(runnable)
+ // Try to fix PyCharm double startup indexing :(
val openWhenSmart = {
DumbService.getInstance(myLearnProject).runWhenSmart {
openLessonForPreparedProject(myLearnProject, lesson)
diff --git a/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt b/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt
index 45c7814bf2d8..ad3f607ca167 100644
--- a/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt
+++ b/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt
@@ -106,8 +106,8 @@ object ProjectUtils {
}
fun simpleInstallAndOpenLearningProject(projectPath: Path,
- projectToClose: Project?,
langSupport: LangSupport,
+ openProjectTask: OpenProjectTask,
postInitCallback: (learnProject: Project) -> Unit) {
val copied = copyLearningProjectFiles(projectPath, langSupport)
if (!copied) return
@@ -115,7 +115,7 @@ object ProjectUtils {
val projectDirectoryVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByNioFile(projectPath)
?: error("Copied Learn project folder is null")
invokeLater {
- val project = ProjectUtil.openOrImport(projectDirectoryVirtualFile.toNioPath(), OpenProjectTask(projectToClose = projectToClose))
+ val project = ProjectUtil.openOrImport(projectDirectoryVirtualFile.toNioPath(), openProjectTask)
?: error("Could not create project for ${langSupport.primaryLanguage}")
PropertiesComponent.getInstance(project).setValue(LEARNING_PROJECT_MODIFICATION, System.currentTimeMillis().toString())
postInitCallback(project)
diff --git a/python/python-features-trainer/intellij.python.featuresTrainer.iml b/python/python-features-trainer/intellij.python.featuresTrainer.iml
index 65199bfaaf02..5acb56445e52 100644
--- a/python/python-features-trainer/intellij.python.featuresTrainer.iml
+++ b/python/python-features-trainer/intellij.python.featuresTrainer.iml
@@ -16,6 +16,5 @@
-
diff --git a/python/python-features-trainer/resources/META-INF/python-features-trainer.xml b/python/python-features-trainer/resources/META-INF/python-features-trainer.xml
index bb5763492891..e296aa263164 100644
--- a/python/python-features-trainer/resources/META-INF/python-features-trainer.xml
+++ b/python/python-features-trainer/resources/META-INF/python-features-trainer.xml
@@ -4,4 +4,9 @@
+
+
+
+
diff --git a/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLangSupport.kt b/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLangSupport.kt
index f5f4c136a5e4..2c249e925cc5 100644
--- a/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLangSupport.kt
+++ b/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLangSupport.kt
@@ -1,6 +1,7 @@
// 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.ift
+import com.intellij.ide.impl.OpenProjectTask
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
@@ -8,17 +9,23 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
+import com.jetbrains.python.configuration.PyConfigurableInterpreterList
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.sdk.*
import com.jetbrains.python.sdk.configuration.PyProjectSdkConfiguration.setReadyToUseSdk
+import com.jetbrains.python.sdk.configuration.PyProjectVirtualEnvConfiguration
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import com.jetbrains.python.statistics.modules
import training.lang.AbstractLangSupport
import training.learn.LearnBundle
import training.learn.exceptons.NoSdkException
+import training.learn.lesson.kimpl.LessonUtil
+import training.project.ProjectUtils
import java.nio.file.Path
class PythonLangSupport : AbstractLangSupport() {
@@ -51,7 +58,26 @@ class PythonLangSupport : AbstractLangSupport() {
}
}
+ override fun installAndOpenLearningProject(projectPath: Path,
+ projectToClose: Project?,
+ postInitCallback: (learnProject: Project) -> Unit) {
+ // if we open project with isProjectCreatedFromWizard flag as true, PythonSdkConfigurator will not run and configure our sdks
+ // and we will configure it individually without any race conditions
+ val openProjectTask = OpenProjectTask(projectToClose = projectToClose, isProjectCreatedWithWizard = true)
+ ProjectUtils.simpleInstallAndOpenLearningProject(projectPath, this, openProjectTask, postInitCallback)
+ }
+
override fun getSdkForProject(project: Project): Sdk? {
+ if (project.pythonSdk != null) return null // sdk already configured
+ return if (useVenv) {
+ createVenv(project)
+ }
+ else {
+ findSystemWideSdk(project)
+ }
+ }
+
+ private fun findSystemWideSdk(project: Project): Sdk? {
val sdkList = ProgressManager.getInstance().runProcessWithProgressSynchronously, Exception>(
{ findAllPythonSdks(Path.of(project.basePath)) },
LearnBundle.message("learn.project.initializing.python.sdk.finding.progress.title"),
@@ -74,6 +100,37 @@ class PythonLangSupport : AbstractLangSupport() {
return preferredSdk
}
+ private fun createVenv(project: Project): Sdk? {
+ val module = project.modules.first()
+ val existingSdks = getExistingSdks()
+ val baseSdks = findBaseSdks(existingSdks, module, project)
+ val preferredSdk = PyProjectVirtualEnvConfiguration.findPreferredVirtualEnvBaseSdk(baseSdks)
+ val venvRoot = FileUtil.toSystemDependentName(PySdkSettings.instance.getPreferredVirtualEnvBasePath(project.basePath))
+ val venvSdk = PyProjectVirtualEnvConfiguration.createVirtualEnvSynchronously(preferredSdk, existingSdks, venvRoot,
+ project.basePath, project, module, project)
+ return venvSdk?.also {
+ SdkConfigurationUtil.addSdk(it)
+ }
+ }
+
+ override fun applyProjectSdk(sdk: Sdk, project: Project) {
+ setReadyToUseSdk(project, project.modules.first(), sdk)
+ if (!useVenv && LessonUtil.productName != defaultProductName) {
+ // This is a workaround for IDEA SetupJavaProjectFromSourcesActivity that replaces our SDK with Java SDK
+ val rootManager = ProjectRootManagerEx.getInstanceEx(project)
+ rootManager.addProjectJdkListener {
+ if (rootManager.projectSdk?.sdkType !is PythonSdkType) {
+ setReadyToUseSdk(project, project.modules.first(), sdk)
+ }
+ }
+ }
+ }
+
+ private fun getExistingSdks(): List {
+ return PyConfigurableInterpreterList.getInstance(null).allPythonSdks
+ .sortedWith(PreferredSdkComparator.INSTANCE)
+ }
+
private fun isNoOlderThan27(sdk: Sdk): Boolean {
val languageLevel = if (sdk is PyDetectedSdk) {
sdk.guessedLanguageLevel
@@ -84,15 +141,8 @@ class PythonLangSupport : AbstractLangSupport() {
return languageLevel?.isAtLeast(LanguageLevel.PYTHON27) ?: false
}
- override fun applyProjectSdk(sdk: Sdk, project: Project) {
- setReadyToUseSdk(project, project.modules.first(), sdk)
- val rootManager = ProjectRootManagerEx.getInstanceEx(project)
- rootManager.addProjectJdkListener {
- if (rootManager.projectSdk?.sdkType !is PythonSdkType) {
- setReadyToUseSdk(project, project.modules.first(), sdk)
- }
- }
- }
+ private val useVenv: Boolean
+ get() = Registry.`is`("ide.features.trainer.use.venv")
override fun checkSdk(sdk: Sdk?, project: Project) {
}