mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +07:00
PY-77813: Report new project type broken in NPW.
FUS statistics consists of two parts:
1. Interpreter (i.e "venv" or "conda")
2. Project generator type ("Django" or "Flask")
`com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector.GENERATOR_FIELD` was a class without any limitation and `DirectoryProjectGenerator` instance was reported (i.e one for Django).
When migrated to NPW, we:
1. Dropped most old generator classes
2. Called this function providing `this::class` by accident, and it was `CoroutineScope`, so we finished with lots of `CoroutineScope` as generator type in FUS.
We must:
1. Provide old names for project types to preserve statistics.
2. Make it type-safe this time.
We also found that interpreter statistics is nullable for `PySdkCreator` which isn't true: SDK creation statistics is always not null.
So we:
* Introduce interface for project generators that reports "name for the statistics"
* Implement it both for DS and PyCharm by returning class name by default
* Overwrite it for several well-known generators to preserve statistics (use old named of now-deleted classes)
* Make interpreter statistics not null.
(cherry picked from commit bdfa73ba043d3584c6ba1871bca7a464a550bc21)
KT-CR-19191
GitOrigin-RevId: 53f874c18d67d33083cf8508a58be257b5e89ab7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fa7590530b
commit
5666495862
@@ -1,15 +1,22 @@
|
|||||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
package com.intellij.pycharm.community.ide.impl.newProjectWizard.impl.emptyProject
|
package com.intellij.pycharm.community.ide.impl.newProjectWizard.impl.emptyProject
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.NlsSafe
|
||||||
import com.jetbrains.python.newProjectWizard.PyV3ProjectBaseGenerator
|
import com.jetbrains.python.newProjectWizard.PyV3ProjectBaseGenerator
|
||||||
import com.jetbrains.python.PyBundle
|
import com.jetbrains.python.PyBundle
|
||||||
|
import com.jetbrains.python.newProjectWizard.collector.PyProjectTypeValidationRule
|
||||||
import com.jetbrains.python.psi.icons.PythonPsiApiIcons
|
import com.jetbrains.python.psi.icons.PythonPsiApiIcons
|
||||||
|
import org.jetbrains.annotations.ApiStatus.Internal
|
||||||
import org.jetbrains.annotations.Nls
|
import org.jetbrains.annotations.Nls
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
internal class PyV3EmptyProjectGenerator : PyV3ProjectBaseGenerator<PyV3EmptyProjectSettings>(
|
@Internal
|
||||||
|
class PyV3EmptyProjectGenerator : PyV3ProjectBaseGenerator<PyV3EmptyProjectSettings>(
|
||||||
PyV3EmptyProjectSettings(generateWelcomeScript = false), PyV3EmptyProjectUI, _newProjectName = "PythonProject") {
|
PyV3EmptyProjectSettings(generateWelcomeScript = false), PyV3EmptyProjectUI, _newProjectName = "PythonProject") {
|
||||||
override fun getName(): @Nls String = PyBundle.message("pure.python.project")
|
override fun getName(): @Nls String = PyBundle.message("pure.python.project")
|
||||||
|
|
||||||
override fun getLogo(): Icon = PythonPsiApiIcons.Python
|
override fun getLogo(): Icon = PythonPsiApiIcons.Python
|
||||||
|
|
||||||
|
|
||||||
|
override val projectTypeForStatistics: @NlsSafe String = PyProjectTypeValidationRule.EMPTY_PROJECT_TYPE_ID
|
||||||
}
|
}
|
||||||
@@ -158,5 +158,7 @@
|
|||||||
<orderEntry type="library" name="kotlinx-datetime-jvm" level="project" />
|
<orderEntry type="library" name="kotlinx-datetime-jvm" level="project" />
|
||||||
<orderEntry type="module" module-name="intellij.platform.ide.remote" />
|
<orderEntry type="module" module-name="intellij.platform.ide.remote" />
|
||||||
<orderEntry type="module" module-name="intellij.platform.ide.ui" />
|
<orderEntry type="module" module-name="intellij.platform.ide.ui" />
|
||||||
|
<orderEntry type="library" name="jackson-module-kotlin" level="project" />
|
||||||
|
<orderEntry type="library" name="ap-validation" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -510,6 +510,7 @@ The Python plug-in provides smart editing for Python scripts. The feature set of
|
|||||||
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.namespacePackages.PyNamespacePackagesStatisticsCollector"/>
|
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.namespacePackages.PyNamespacePackagesStatisticsCollector"/>
|
||||||
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.codeInsight.codeVision.PyCodeVisionUsageCollector"/>
|
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.codeInsight.codeVision.PyCodeVisionUsageCollector"/>
|
||||||
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector"/>
|
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector"/>
|
||||||
|
<statistics.validation.customValidationRule implementation="com.jetbrains.python.newProjectWizard.collector.PyProjectTypeValidationRule"/>
|
||||||
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.sdk.add.collector.PythonNewInterpreterAddedCollector"/>
|
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.sdk.add.collector.PythonNewInterpreterAddedCollector"/>
|
||||||
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.run.runAnything.PyRunAnythingCollector"/>
|
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.run.runAnything.PyRunAnythingCollector"/>
|
||||||
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.debugger.statistics.PyDataViewerCollector"/>
|
<statistics.counterUsagesCollector implementationClass="com.jetbrains.python.debugger.statistics.PyDataViewerCollector"/>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project;
|
|||||||
import com.intellij.openapi.projectRoots.Sdk;
|
import com.intellij.openapi.projectRoots.Sdk;
|
||||||
import com.intellij.openapi.ui.Messages;
|
import com.intellij.openapi.ui.Messages;
|
||||||
import com.intellij.openapi.util.NlsContexts.DialogMessage;
|
import com.intellij.openapi.util.NlsContexts.DialogMessage;
|
||||||
|
import com.intellij.openapi.util.NlsSafe;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.platform.DirectoryProjectGeneratorBase;
|
import com.intellij.platform.DirectoryProjectGeneratorBase;
|
||||||
@@ -22,6 +23,7 @@ import com.intellij.util.containers.ContainerUtil;
|
|||||||
import com.jetbrains.python.PyBundle;
|
import com.jetbrains.python.PyBundle;
|
||||||
import com.jetbrains.python.PyPsiPackageUtil;
|
import com.jetbrains.python.PyPsiPackageUtil;
|
||||||
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo;
|
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo;
|
||||||
|
import com.jetbrains.python.newProjectWizard.collector.PyProjectTypeGenerator;
|
||||||
import com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector;
|
import com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector;
|
||||||
import com.jetbrains.python.packaging.PyPackage;
|
import com.jetbrains.python.packaging.PyPackage;
|
||||||
import com.jetbrains.python.packaging.PyPackageManager;
|
import com.jetbrains.python.packaging.PyPackageManager;
|
||||||
@@ -49,7 +51,8 @@ import java.util.function.Consumer;
|
|||||||
* @deprecated Use {@link com.jetbrains.python.newProjectWizard}
|
* @deprecated Use {@link com.jetbrains.python.newProjectWizard}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public abstract class PythonProjectGenerator<T extends PyNewProjectSettings> extends DirectoryProjectGeneratorBase<T> {
|
public abstract class PythonProjectGenerator<T extends PyNewProjectSettings> extends DirectoryProjectGeneratorBase<T> implements
|
||||||
|
PyProjectTypeGenerator {
|
||||||
public static final PyNewProjectSettings NO_SETTINGS = new PyNewProjectSettings();
|
public static final PyNewProjectSettings NO_SETTINGS = new PyNewProjectSettings();
|
||||||
private static final Logger LOGGER = Logger.getInstance(PythonProjectGenerator.class);
|
private static final Logger LOGGER = Logger.getInstance(PythonProjectGenerator.class);
|
||||||
|
|
||||||
@@ -72,6 +75,11 @@ public abstract class PythonProjectGenerator<T extends PyNewProjectSettings> ext
|
|||||||
this(false, null);
|
this(false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final @NlsSafe @NotNull String getProjectTypeForStatistics() {
|
||||||
|
return getClass().getName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param allowRemoteProjectCreation if project of this type could be created remotely
|
* @param allowRemoteProjectCreation if project of this type could be created remotely
|
||||||
* @param preferredInterpreter interpreter type to select by default
|
* @param preferredInterpreter interpreter type to select by default
|
||||||
@@ -179,7 +187,7 @@ public abstract class PythonProjectGenerator<T extends PyNewProjectSettings> ext
|
|||||||
if (statisticsInfo instanceof InterpreterStatisticsInfo interpreterStatisticsInfo && settings.getSdk() != null) {
|
if (statisticsInfo instanceof InterpreterStatisticsInfo interpreterStatisticsInfo && settings.getSdk() != null) {
|
||||||
PythonNewProjectWizardCollector.logPythonNewProjectGenerated(interpreterStatisticsInfo,
|
PythonNewProjectWizardCollector.logPythonNewProjectGenerated(interpreterStatisticsInfo,
|
||||||
PyStatisticToolsKt.getVersion(settings.getSdk()),
|
PyStatisticToolsKt.getVersion(settings.getSdk()),
|
||||||
this.getClass(),
|
this,
|
||||||
Collections.emptyList());
|
Collections.emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,20 @@
|
|||||||
package com.jetbrains.python.newProjectWizard
|
package com.jetbrains.python.newProjectWizard
|
||||||
|
|
||||||
import com.intellij.openapi.GitRepositoryInitializer
|
import com.intellij.openapi.GitRepositoryInitializer
|
||||||
import com.intellij.openapi.application.EDT
|
|
||||||
import com.intellij.openapi.module.Module
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.openapi.projectRoots.Sdk
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.platform.ide.progress.withBackgroundProgress
|
import com.intellij.platform.ide.progress.withBackgroundProgress
|
||||||
import com.jetbrains.python.PyBundle
|
import com.jetbrains.python.PyBundle
|
||||||
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
||||||
import com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector.logPythonNewProjectGenerated
|
|
||||||
import com.jetbrains.python.sdk.ModuleOrProject
|
import com.jetbrains.python.sdk.ModuleOrProject
|
||||||
import com.jetbrains.python.sdk.add.v2.PySdkCreator
|
import com.jetbrains.python.sdk.add.v2.PySdkCreator
|
||||||
import com.jetbrains.python.sdk.pythonSdk
|
import com.jetbrains.python.sdk.pythonSdk
|
||||||
import com.jetbrains.python.sdk.setAssociationToModule
|
import com.jetbrains.python.sdk.setAssociationToModule
|
||||||
import com.jetbrains.python.statistics.version
|
import kotlinx.coroutines.CoroutineName
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings each Python project has: [sdkCreator] and [createGitRepository]
|
* Settings each Python project has: [sdkCreator] and [createGitRepository]
|
||||||
@@ -23,7 +23,7 @@ import kotlinx.coroutines.*
|
|||||||
class PyV3BaseProjectSettings(var createGitRepository: Boolean = false) {
|
class PyV3BaseProjectSettings(var createGitRepository: Boolean = false) {
|
||||||
lateinit var sdkCreator: PySdkCreator
|
lateinit var sdkCreator: PySdkCreator
|
||||||
|
|
||||||
suspend fun generateAndGetSdk(module: Module, baseDir: VirtualFile): Result<Sdk> = coroutineScope {
|
suspend fun generateAndGetSdk(module: Module, baseDir: VirtualFile): Result<Pair<Sdk, InterpreterStatisticsInfo>> = coroutineScope {
|
||||||
val project = module.project
|
val project = module.project
|
||||||
if (createGitRepository) {
|
if (createGitRepository) {
|
||||||
launch(CoroutineName("Generating git") + Dispatchers.IO) {
|
launch(CoroutineName("Generating git") + Dispatchers.IO) {
|
||||||
@@ -32,22 +32,14 @@ class PyV3BaseProjectSettings(var createGitRepository: Boolean = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val (sdk: Sdk, statistics: InterpreterStatisticsInfo?) = getSdkAndInterpreter(module).getOrElse { return@coroutineScope Result.failure(it) }
|
val (sdk: Sdk, interpreterStatistics: InterpreterStatisticsInfo) = getSdkAndInterpreter(module).getOrElse { return@coroutineScope Result.failure(it) }
|
||||||
sdk.setAssociationToModule(module)
|
sdk.setAssociationToModule(module)
|
||||||
module.pythonSdk = sdk
|
module.pythonSdk = sdk
|
||||||
if (statistics != null) {
|
return@coroutineScope Result.success(Pair(sdk, interpreterStatistics))
|
||||||
logPythonNewProjectGenerated(statistics,
|
|
||||||
sdk.version,
|
|
||||||
this::class.java,
|
|
||||||
emptyList())
|
|
||||||
}
|
|
||||||
return@coroutineScope Result.success(sdk)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSdkAndInterpreter(module: Module): Result<Pair<Sdk, InterpreterStatisticsInfo?>> = withContext(Dispatchers.EDT) {
|
private suspend fun getSdkAndInterpreter(module: Module): Result<Pair<Sdk, InterpreterStatisticsInfo>> =
|
||||||
val sdk: Sdk = sdkCreator.getSdk(ModuleOrProject.ModuleAndProject(module)).getOrElse { return@withContext Result.failure(it) }
|
sdkCreator.getSdk(ModuleOrProject.ModuleAndProject(module))
|
||||||
return@withContext Result.success(Pair<Sdk, InterpreterStatisticsInfo?>(sdk, sdkCreator.createStatisticsInfo()))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
|||||||
@@ -14,17 +14,19 @@ import com.intellij.openapi.vfs.VirtualFile
|
|||||||
import com.intellij.platform.DirectoryProjectGenerator
|
import com.intellij.platform.DirectoryProjectGenerator
|
||||||
import com.intellij.platform.ProjectGeneratorPeer
|
import com.intellij.platform.ProjectGeneratorPeer
|
||||||
import com.jetbrains.python.Result
|
import com.jetbrains.python.Result
|
||||||
|
import com.jetbrains.python.newProjectWizard.collector.PyProjectTypeGenerator
|
||||||
|
import com.jetbrains.python.newProjectWizard.collector.PythonNewProjectWizardCollector.logPythonNewProjectGenerated
|
||||||
import com.jetbrains.python.newProjectWizard.impl.PyV3GeneratorPeer
|
import com.jetbrains.python.newProjectWizard.impl.PyV3GeneratorPeer
|
||||||
import com.jetbrains.python.newProjectWizard.projectPath.ProjectPathFlows.Companion.validatePath
|
import com.jetbrains.python.newProjectWizard.projectPath.ProjectPathFlows.Companion.validatePath
|
||||||
import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMode
|
import com.jetbrains.python.sdk.add.v2.PythonInterpreterSelectionMode
|
||||||
|
import com.jetbrains.python.statistics.version
|
||||||
import com.jetbrains.python.util.ErrorSink
|
import com.jetbrains.python.util.ErrorSink
|
||||||
import com.jetbrains.python.util.ShowingMessageErrorSync
|
import com.jetbrains.python.util.ShowingMessageErrorSync
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jetbrains.annotations.Nls
|
import kotlin.reflect.jvm.jvmName
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend this class to register a new project generator.
|
* Extend this class to register a new project generator.
|
||||||
@@ -41,15 +43,16 @@ abstract class PyV3ProjectBaseGenerator<TYPE_SPECIFIC_SETTINGS : PyV3ProjectType
|
|||||||
private val errorSink: ErrorSink = ShowingMessageErrorSync,
|
private val errorSink: ErrorSink = ShowingMessageErrorSync,
|
||||||
private val _newProjectName: @NlsSafe String? = null,
|
private val _newProjectName: @NlsSafe String? = null,
|
||||||
private val expandProjectAfterCreation: Boolean = !ApplicationManager.getApplication().isHeadlessEnvironment,
|
private val expandProjectAfterCreation: Boolean = !ApplicationManager.getApplication().isHeadlessEnvironment,
|
||||||
) : DirectoryProjectGenerator<PyV3BaseProjectSettings> {
|
) : DirectoryProjectGenerator<PyV3BaseProjectSettings>, PyProjectTypeGenerator {
|
||||||
private val baseSettings = PyV3BaseProjectSettings()
|
private val baseSettings = PyV3BaseProjectSettings()
|
||||||
val newProjectName: @NlsSafe String get() = _newProjectName ?: "${name.replace(" ", "")}Project"
|
val newProjectName: @NlsSafe String get() = _newProjectName ?: "${name.replace(" ", "")}Project"
|
||||||
|
|
||||||
|
override val projectTypeForStatistics: @NlsSafe String = this::class.jvmName
|
||||||
|
|
||||||
override fun generateProject(project: Project, baseDir: VirtualFile, settings: PyV3BaseProjectSettings, module: Module) {
|
override fun generateProject(project: Project, baseDir: VirtualFile, settings: PyV3BaseProjectSettings, module: Module) {
|
||||||
val coroutineScope = project.service<MyService>().coroutineScope
|
val coroutineScope = project.service<MyService>().coroutineScope
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val sdk = settings.generateAndGetSdk(module, baseDir).getOrElse {
|
val (sdk, interpreterStatistics) = settings.generateAndGetSdk(module, baseDir).getOrElse {
|
||||||
withContext(Dispatchers.EDT) {
|
withContext(Dispatchers.EDT) {
|
||||||
errorSink.emit(it.localizedMessage) // Show error generation to user
|
errorSink.emit(it.localizedMessage) // Show error generation to user
|
||||||
}
|
}
|
||||||
@@ -58,6 +61,14 @@ abstract class PyV3ProjectBaseGenerator<TYPE_SPECIFIC_SETTINGS : PyV3ProjectType
|
|||||||
// Project view must be expanded (PY-75909) but it can't be unless it contains some files.
|
// Project view must be expanded (PY-75909) but it can't be unless it contains some files.
|
||||||
// Either base settings (which create venv) might generate some or type specific settings (like Django) may.
|
// Either base settings (which create venv) might generate some or type specific settings (like Django) may.
|
||||||
// So we expand it right after SDK generation, but if there are no files yet, we do it again after project generation
|
// So we expand it right after SDK generation, but if there are no files yet, we do it again after project generation
|
||||||
|
|
||||||
|
|
||||||
|
val pythonVersion = withContext(Dispatchers.IO) { sdk.version }
|
||||||
|
logPythonNewProjectGenerated(interpreterStatistics,
|
||||||
|
pythonVersion,
|
||||||
|
this@PyV3ProjectBaseGenerator,
|
||||||
|
emptyList())
|
||||||
|
|
||||||
ensureProjectViewExpanded(project)
|
ensureProjectViewExpanded(project)
|
||||||
typeSpecificSettings.generateProject(module, baseDir, sdk).onFailure { errorSink.emit(it.localizedMessage) }
|
typeSpecificSettings.generateProject(module, baseDir, sdk).onFailure { errorSink.emit(it.localizedMessage) }
|
||||||
ensureProjectViewExpanded(project)
|
ensureProjectViewExpanded(project)
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package com.jetbrains.python.newProjectWizard.collector
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.NlsSafe
|
||||||
|
import org.jetbrains.annotations.ApiStatus
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [com.intellij.platform.DirectoryProjectGenerator] for something python-specific.
|
||||||
|
* You must implement both [com.intellij.platform.DirectoryProjectGenerator] and this interface.
|
||||||
|
*
|
||||||
|
* This interface is a part of internal JetBrains infrastructure.
|
||||||
|
* Extend [com.jetbrains.python.newProjectWizard.PyV3ProjectBaseGenerator] instead.
|
||||||
|
*/
|
||||||
|
@ApiStatus.Internal
|
||||||
|
interface PyProjectTypeGenerator {
|
||||||
|
/**
|
||||||
|
* Project type for FUS, see [PythonNewProjectWizardCollector.GENERATOR_FIELD].
|
||||||
|
* Try not to change it ofter not to break statistics.
|
||||||
|
*
|
||||||
|
* This property is for JetBrains plugins only and will be ignored for other plugins.
|
||||||
|
* Do not overwrite it if you aren't JetBrains employee.
|
||||||
|
*/
|
||||||
|
val projectTypeForStatistics: @NlsSafe String
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
package com.jetbrains.python.newProjectWizard.collector
|
||||||
|
|
||||||
|
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep
|
||||||
|
import com.intellij.internal.statistic.eventLog.validator.ValidationResultType
|
||||||
|
import com.intellij.internal.statistic.eventLog.validator.rules.EventContext
|
||||||
|
import com.intellij.internal.statistic.eventLog.validator.rules.impl.CustomValidationRule
|
||||||
|
import com.intellij.internal.statistic.utils.getPluginInfo
|
||||||
|
import com.jetbrains.python.newProjectWizard.collector.PyProjectTypeValidationRule.Companion.EMPTY_PROJECT_TYPE_ID
|
||||||
|
import org.jetbrains.annotations.ApiStatus.Internal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures project type provided to [doValidate] is [PyProjectTypeGenerator.projectTypeForStatistics]
|
||||||
|
*/
|
||||||
|
@Internal
|
||||||
|
class PyProjectTypeValidationRule : CustomValidationRule() {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* [com.intellij.platform.DirectoryProjectGenerator] for default (empty, base) project type isn't registered in EP, hence hardcoded
|
||||||
|
*/
|
||||||
|
const val EMPTY_PROJECT_TYPE_ID = "com.intellij.pycharm.community.ide.impl.newProject.steps.PythonBaseProjectGenerator"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRuleId(): String = "python_new_project_type"
|
||||||
|
|
||||||
|
override fun doValidate(data: String, context: EventContext): ValidationResultType = validate(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
fun validate(data: String): ValidationResultType {
|
||||||
|
val valid = data == EMPTY_PROJECT_TYPE_ID || AbstractNewProjectStep.EP_NAME
|
||||||
|
.extensionList
|
||||||
|
.filterIsInstance<PyProjectTypeGenerator>()
|
||||||
|
.any { getPluginInfo(it::class.java).isDevelopedByJetBrains() && it.projectTypeForStatistics == data }
|
||||||
|
return if (valid) ValidationResultType.ACCEPTED else ValidationResultType.REJECTED
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import com.intellij.internal.statistic.eventLog.events.EventFields.createAdditio
|
|||||||
import com.intellij.internal.statistic.eventLog.events.EventPair
|
import com.intellij.internal.statistic.eventLog.events.EventPair
|
||||||
import com.intellij.internal.statistic.eventLog.events.ObjectEventData
|
import com.intellij.internal.statistic.eventLog.events.ObjectEventData
|
||||||
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
|
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
|
||||||
|
import com.intellij.platform.DirectoryProjectGenerator
|
||||||
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
||||||
import com.jetbrains.python.psi.LanguageLevel
|
import com.jetbrains.python.psi.LanguageLevel
|
||||||
import com.jetbrains.python.statistics.EXECUTION_TYPE
|
import com.jetbrains.python.statistics.EXECUTION_TYPE
|
||||||
@@ -22,13 +23,13 @@ object PythonNewProjectWizardCollector : CounterUsagesCollector() {
|
|||||||
return GROUP
|
return GROUP
|
||||||
}
|
}
|
||||||
|
|
||||||
private val GROUP = EventLogGroup("python.new.project.wizard", 9)
|
private val GROUP = EventLogGroup("python.new.project.wizard", 10)
|
||||||
const val PROJECT_GENERATED_EVENT_ID = "project.generated"
|
const val PROJECT_GENERATED_EVENT_ID = "project.generated"
|
||||||
private val INHERIT_GLOBAL_SITE_PACKAGE_FIELD = EventFields.Boolean("inherit_global_site_package")
|
private val INHERIT_GLOBAL_SITE_PACKAGE_FIELD = EventFields.Boolean("inherit_global_site_package")
|
||||||
private val MAKE_AVAILABLE_TO_ALL_PROJECTS = EventFields.Boolean("make_available_to_all_projects")
|
private val MAKE_AVAILABLE_TO_ALL_PROJECTS = EventFields.Boolean("make_available_to_all_projects")
|
||||||
private val PREVIOUSLY_CONFIGURED = EventFields.Boolean("previously_configured")
|
private val PREVIOUSLY_CONFIGURED = EventFields.Boolean("previously_configured")
|
||||||
private val IS_WSL_CONTEXT = EventFields.Boolean("wsl_context")
|
private val IS_WSL_CONTEXT = EventFields.Boolean("wsl_context")
|
||||||
private val GENERATOR_FIELD = EventFields.Class("generator")
|
private val GENERATOR_FIELD = EventFields.StringValidatedByCustomRule("generator", PyProjectTypeValidationRule::class.java)
|
||||||
private val DJANGO_ADMIN_FIELD = EventFields.Boolean("django_admin")
|
private val DJANGO_ADMIN_FIELD = EventFields.Boolean("django_admin")
|
||||||
private val ADDITIONAL = createAdditionalDataField(GROUP.id, PROJECT_GENERATED_EVENT_ID)
|
private val ADDITIONAL = createAdditionalDataField(GROUP.id, PROJECT_GENERATED_EVENT_ID)
|
||||||
|
|
||||||
@@ -50,12 +51,12 @@ object PythonNewProjectWizardCollector : CounterUsagesCollector() {
|
|||||||
private val USE_EXISTING_VENV_FIX = GROUP.registerEvent("existing.venv")
|
private val USE_EXISTING_VENV_FIX = GROUP.registerEvent("existing.venv")
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun logPythonNewProjectGenerated(
|
fun <T> logPythonNewProjectGenerated(
|
||||||
info: InterpreterStatisticsInfo,
|
info: InterpreterStatisticsInfo,
|
||||||
pythonVersion: LanguageLevel,
|
pythonVersion: LanguageLevel,
|
||||||
generatorClass: Class<*>,
|
generator: T,
|
||||||
additionalData: List<EventPair<*>>,
|
additionalData: List<EventPair<*>>,
|
||||||
) {
|
) where T : PyProjectTypeGenerator, T : DirectoryProjectGenerator<*> {
|
||||||
PROJECT_GENERATED_EVENT.log(
|
PROJECT_GENERATED_EVENT.log(
|
||||||
INTERPRETER_TYPE.with(info.type.value),
|
INTERPRETER_TYPE.with(info.type.value),
|
||||||
EXECUTION_TYPE.with(info.target.value),
|
EXECUTION_TYPE.with(info.target.value),
|
||||||
@@ -64,7 +65,7 @@ object PythonNewProjectWizardCollector : CounterUsagesCollector() {
|
|||||||
INHERIT_GLOBAL_SITE_PACKAGE_FIELD.with(info.globalSitePackage),
|
INHERIT_GLOBAL_SITE_PACKAGE_FIELD.with(info.globalSitePackage),
|
||||||
MAKE_AVAILABLE_TO_ALL_PROJECTS.with(info.makeAvailableToAllProjects),
|
MAKE_AVAILABLE_TO_ALL_PROJECTS.with(info.makeAvailableToAllProjects),
|
||||||
PREVIOUSLY_CONFIGURED.with(info.previouslyConfigured),
|
PREVIOUSLY_CONFIGURED.with(info.previouslyConfigured),
|
||||||
GENERATOR_FIELD.with(generatorClass),
|
GENERATOR_FIELD.with(generator.projectTypeForStatistics),
|
||||||
IS_WSL_CONTEXT.with(info.isWSLContext),
|
IS_WSL_CONTEXT.with(info.isWSLContext),
|
||||||
ADDITIONAL.with(ObjectEventData(additionalData))
|
ADDITIONAL.with(ObjectEventData(additionalData))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
|
@ApiStatus.Internal
|
||||||
|
package com.jetbrains.python.newProjectWizard.collector;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
package com.jetbrains.python.sdk.add.v2
|
package com.jetbrains.python.sdk.add.v2
|
||||||
|
|
||||||
import com.intellij.openapi.projectRoots.Sdk
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
|
||||||
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
||||||
import com.jetbrains.python.sdk.ModuleOrProject
|
import com.jetbrains.python.sdk.ModuleOrProject
|
||||||
|
|
||||||
@@ -10,8 +9,5 @@ interface PySdkCreator {
|
|||||||
/**
|
/**
|
||||||
* Error is shown to user. Do not catch all exceptions, only return exceptions valuable to user
|
* Error is shown to user. Do not catch all exceptions, only return exceptions valuable to user
|
||||||
*/
|
*/
|
||||||
suspend fun getSdk(moduleOrProject: ModuleOrProject): Result<Sdk>
|
suspend fun getSdk(moduleOrProject: ModuleOrProject): Result<Pair<Sdk, InterpreterStatisticsInfo>>
|
||||||
|
|
||||||
@RequiresEdt
|
|
||||||
fun createStatisticsInfo(): InterpreterStatisticsInfo? = null
|
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ import com.intellij.ui.dsl.builder.AlignX
|
|||||||
import com.intellij.ui.dsl.builder.Panel
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
import com.intellij.ui.dsl.builder.TopGap
|
import com.intellij.ui.dsl.builder.TopGap
|
||||||
import com.intellij.ui.dsl.builder.bindText
|
import com.intellij.ui.dsl.builder.bindText
|
||||||
|
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||||
import com.intellij.util.ui.showingScope
|
import com.intellij.util.ui.showingScope
|
||||||
import com.jetbrains.python.PyBundle.message
|
import com.jetbrains.python.PyBundle.message
|
||||||
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
import com.jetbrains.python.newProject.collector.InterpreterStatisticsInfo
|
||||||
@@ -158,12 +159,12 @@ class PythonAddNewEnvironmentPanel(val projectPathFlows: ProjectPathFlows, onlyA
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
runBlockingCancellable { getSdk(moduleOrProject) }
|
runBlockingCancellable { getSdk(moduleOrProject) }
|
||||||
}.getOrThrow()
|
}.getOrThrow().first
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getSdk(moduleOrProject: ModuleOrProject): Result<Sdk> {
|
override suspend fun getSdk(moduleOrProject: ModuleOrProject): Result<Pair<Sdk, InterpreterStatisticsInfo>> {
|
||||||
model.navigator.saveLastState()
|
model.navigator.saveLastState()
|
||||||
return when (selectedMode.get()) {
|
val sdk = when (selectedMode.get()) {
|
||||||
PROJECT_VENV -> {
|
PROJECT_VENV -> {
|
||||||
val projectPath = projectPathFlows.projectPathWithDefault.first()
|
val projectPath = projectPathFlows.projectPathWithDefault.first()
|
||||||
// todo just keep venv path, all the rest is in the model
|
// todo just keep venv path, all the rest is in the model
|
||||||
@@ -171,11 +172,13 @@ class PythonAddNewEnvironmentPanel(val projectPathFlows: ProjectPathFlows, onlyA
|
|||||||
}
|
}
|
||||||
BASE_CONDA -> model.selectCondaEnvironment(base = true)
|
BASE_CONDA -> model.selectCondaEnvironment(base = true)
|
||||||
CUSTOM -> custom.currentSdkManager.getOrCreateSdk(moduleOrProject)
|
CUSTOM -> custom.currentSdkManager.getOrCreateSdk(moduleOrProject)
|
||||||
}
|
}.getOrElse { return Result.failure(it) }
|
||||||
|
val statistics = withContext(Dispatchers.EDT) { createStatisticsInfo() }
|
||||||
|
return Result.success(Pair(sdk, statistics))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresEdt
|
||||||
override fun createStatisticsInfo(): InterpreterStatisticsInfo = when (selectedMode.get()) {
|
fun createStatisticsInfo(): InterpreterStatisticsInfo = when (selectedMode.get()) {
|
||||||
PROJECT_VENV -> InterpreterStatisticsInfo(InterpreterType.VIRTUALENV,
|
PROJECT_VENV -> InterpreterStatisticsInfo(InterpreterType.VIRTUALENV,
|
||||||
InterpreterTarget.LOCAL,
|
InterpreterTarget.LOCAL,
|
||||||
false,
|
false,
|
||||||
|
|||||||
Reference in New Issue
Block a user