Skip to content

Commit

Permalink
Bypass Jvm validations for Gradle execution when project uses Daemon …
Browse files Browse the repository at this point in the history
…toolchain
  • Loading branch information
vmadalin committed Oct 15, 2024
1 parent 2765a95 commit 8aa741b
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ internal class ProjectSdkDataService : AbstractProjectDataService<ProjectSdkData
val sdk = projectJdkTable.findJdk(sdkName)
val projectRootManager = ProjectRootManager.getInstance(project)
val projectSdk = projectRootManager.projectSdk
if (projectSdk == null) {
if (projectSdk != sdk) {
projectRootManager.projectSdk = sdk
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.serialization.JpsSerializationManager
import org.jetbrains.plugins.gradle.GradleManager
import org.jetbrains.plugins.gradle.GradleWarmupConfigurator
import org.jetbrains.plugins.gradle.service.execution.GradleDaemonJvmHelper
import org.jetbrains.plugins.gradle.service.project.open.GradleProjectOpenProcessor
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import java.io.File
Expand Down Expand Up @@ -147,6 +148,7 @@ private fun forceUseProjectJdkForImporter(project: Project, projectDir: VirtualF
println("Found ${allGradleSettings.size} Gradle project settings linked to the project.")

for (settings in allGradleSettings) {
if (GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(settings)) continue
settings.gradleJvm = ExternalSystemJdkUtil.USE_PROJECT_JDK
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.jetbrains.plugins.gradle.model.data.BuildParticipant;
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData;
import org.jetbrains.plugins.gradle.service.GradleInstallationManager;
import org.jetbrains.plugins.gradle.service.execution.GradleDaemonJvmHelper;
import org.jetbrains.plugins.gradle.service.project.GradleAutoImportAware;
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver;
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverExtension;
Expand Down Expand Up @@ -144,7 +145,11 @@ public Function<Pair<Project, String>, GradleExecutionSettings> getExecutionSett
if (!StringUtil.isEmpty(javaHome)) {
LOG.info("Instructing gradle to use java from " + javaHome);
}
result.setJavaHome(javaHome);

if (projectLevelSettings == null || !GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(projectLevelSettings)) {
result.setJavaHome(javaHome);
}

GradleSystemSettings systemSettings = GradleSystemSettings.getInstance();
String vmOptions = Objects.requireNonNullElse(settings.getGradleVmOptions(), "");
if (vmOptions.contains("-Didea.gradle.download.sources.force=false")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ class LocalGradleExecutionAware : GradleExecutionAware {
): SdkInfo? {
val settings = project.lock { GradleSettings.getInstance(it) }
val projectSettings = settings.getLinkedProjectSettings(externalProjectPath) ?: return null
// Projects using Daemon JVM criteria with a compatible Gradle version will skip any
// Gradle JDK configuration validation since this will be delegated to Gradle
if (GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(projectSettings)) return null

val originalGradleJvm = projectSettings.gradleJvm
val provider = project.lock { getGradleJvmLookupProvider(it, projectSettings) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.util.lang.JavaVersion
import org.jetbrains.plugins.gradle.GradleManager
import org.jetbrains.plugins.gradle.jvmcompat.GradleJvmSupportMatrix
import org.jetbrains.plugins.gradle.service.execution.GradleDaemonJvmHelper
import org.jetbrains.plugins.gradle.service.project.GradleNotification
import org.jetbrains.plugins.gradle.service.project.GradleNotificationIdsHolder
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
Expand Down Expand Up @@ -116,6 +117,7 @@ internal class GradleProjectSettingsUpdater : ExternalSystemSettingsListenerEx {
if (manager !is GradleManager) return
for (projectSettings in settings) {
if (projectSettings !is GradleProjectSettings) continue
if (GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(projectSettings)) continue
val statusFuture = Util.updateGradleJvm(project, projectSettings)
statusFuture.thenAccept {
if (it.updated && it.sdkName != null) notifyGradleJvmChangeInfo(project, projectSettings, it.sdkName, it.sdk)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Version
import org.gradle.util.GradleVersion
import org.jetbrains.plugins.gradle.properties.GradlePropertiesFile
import org.jetbrains.plugins.gradle.service.execution.GradleDaemonJvmHelper
import org.jetbrains.plugins.gradle.settings.DistributionType
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.settings.GradleSettings
import org.jetbrains.plugins.gradle.settings.GradleSystemSettings
import org.jetbrains.plugins.gradle.settings.TestRunner
import org.jetbrains.plugins.gradle.util.GradleConstants
import java.nio.file.Path
import java.nio.file.Paths

internal class GradleSettingsCollector : ProjectUsagesCollector() {
Expand Down Expand Up @@ -100,6 +102,7 @@ internal class GradleSettingsCollector : ProjectUsagesCollector() {
?.let { it.jsonString.length > 2 } ?: false

usages.add(IDEA_SPECIFIC_CONFIGURATION_USED.metric(hasNonEmptyIntellijConfig))
usages.add(GRADLE_DAEMON_JVM_CRITERIA_DEFINED.metric(GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(Path.of(projectPath), gradleVersion)))
}

private fun collectGradlePropertiesMetrics(usages: MutableSet<MetricEvent>, project: Project, externalProjectPath: String) {
Expand Down Expand Up @@ -144,6 +147,7 @@ internal class GradleSettingsCollector : ProjectUsagesCollector() {
EventFields.Enum("value", TestRunner::class.java) { it.name.lowercase() })
private val GRADLE_JVM_TYPE = GROUP.registerEvent("gradleJvmType", JRE_TYPE_FIELD)
private val GRADLE_JVM_VERSION = GROUP.registerEvent("gradleJvmVersion", VERSION_FIELD)
private val GRADLE_DAEMON_JVM_CRITERIA_DEFINED = GROUP.registerEvent("gradleDaemonJvmCriteriaDefined", EventFields.Enabled)
private val GRADLE_DOWNLOAD_DEPENDENCY_SOURCES = GROUP.registerEvent("gradleDownloadDependencySources", EventFields.Enabled)
private val GRADLE_PARALLEL_MODEL_FETCH = GROUP.registerEvent("gradleParallelModelFetch", EventFields.Enabled)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.gradle.util.GradleVersion
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.plugins.gradle.jvmcompat.GradleJvmSupportMatrix
import org.jetbrains.plugins.gradle.properties.GradlePropertiesFile
import org.jetbrains.plugins.gradle.service.execution.GradleDaemonJvmHelper
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.settings.GradleSettings
import org.jetbrains.plugins.gradle.util.JavaHomeValidationStatus.Success
Expand All @@ -28,6 +29,10 @@ fun getGradleJvmLookupProvider(project: Project, projectSettings: GradleProjectS
SdkLookupProvider.getInstance(project, GradleJvmProviderId(projectSettings))

fun setupGradleJvm(project: Project, projectSettings: GradleProjectSettings, gradleVersion: GradleVersion) {
// Projects using Daemon JVM criteria with a compatible Gradle version will skip the
// Gradle JVM setup since this will be delegated to Gradle
if (GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(projectSettings)) return

val resolutionContext = GradleJvmResolutionContext(project, Paths.get(projectSettings.externalProjectPath), gradleVersion)
projectSettings.gradleJvm = resolutionContext.findGradleJvm()
if (projectSettings.gradleJvm != null) {
Expand Down Expand Up @@ -85,6 +90,7 @@ fun updateGradleJvm(project: Project, externalProjectPath: String) {
val projectRootManager = ProjectRootManager.getInstance(project)
val projectSdk = projectRootManager.projectSdk ?: return
if (projectSdk.name != gradleJvm) return
if (GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(projectSettings)) return
projectSettings.gradleJvm = ExternalSystemJdkUtil.USE_PROJECT_JDK
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ import org.jetbrains.annotations.ApiStatus
import org.jetbrains.plugins.gradle.jvmcompat.GradleJvmSupportMatrix
import org.jetbrains.plugins.gradle.properties.GradlePropertiesFile
import org.jetbrains.plugins.gradle.properties.models.Property
import org.jetbrains.plugins.gradle.service.execution.GradleDaemonJvmHelper
import org.jetbrains.plugins.gradle.service.project.GradleNotification
import org.jetbrains.plugins.gradle.service.project.GradleNotificationIdsHolder
import java.io.File
import java.nio.file.Path
import javax.swing.event.HyperlinkEvent

fun validateJavaHome(project: Project, externalProjectPath: Path, gradleVersion: GradleVersion) {
// Projects using Daemon JVM criteria with a compatible Gradle version
// will ignore Java Home from environment variables or Gradle Properties
if (GradleDaemonJvmHelper.isProjectUsingDaemonJvmCriteria(externalProjectPath, gradleVersion)) return

val gradleProperties = GradlePropertiesFile.getProperties(project, externalProjectPath)
val javaHomeProperty = gradleProperties.javaHomeProperty
if (javaHomeProperty != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.intellij.openapi.roots.ui.configuration.SdkTestCase.Companion.assertU
import com.intellij.openapi.roots.ui.configuration.SdkTestCase.Companion.withRegisteredSdks
import com.intellij.openapi.roots.ui.configuration.SdkTestCase.TestSdkGenerator
import kotlinx.coroutines.runBlocking
import org.jetbrains.plugins.gradle.tooling.annotation.TargetVersions
import org.junit.Test

class GradleProjectSdkResolverTest : GradleProjectSdkResolverTestCase() {
Expand Down Expand Up @@ -63,4 +64,22 @@ class GradleProjectSdkResolverTest : GradleProjectSdkResolverTestCase() {
}
}
}

@Test
@TargetVersions("8.8+")
fun `test project using Daemon toolchain`() = runBlocking {
val jdk = resolveRealTestSdk()
val sdk = TestSdkGenerator.createNextSdk()
createGradleSubProject()
createDaemonJvmPropertiesFile(jdk)

environment.withVariables(JAVA_HOME to sdk.homePath) {
withRegisteredSdks(jdk, sdk) {
assertUnexpectedSdksRegistration {
loadProject()
assertSdks(jdk, "project", "project.main", "project.test")
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.ui.configuration.SdkTestCase
import com.intellij.openapi.roots.ui.configuration.SdkTestCase.Companion.assertSdk
import com.intellij.openapi.roots.ui.configuration.SdkTestCase.TestSdkGenerator
import com.intellij.testFramework.VfsTestUtil
import com.intellij.testFramework.replaceService
import com.intellij.util.lang.JavaVersion
import org.jetbrains.plugins.gradle.service.project.open.linkAndSyncGradleProject
import org.jetbrains.plugins.gradle.testFramework.util.awaitGradleProjectConfiguration
import org.jetbrains.plugins.gradle.testFramework.util.createBuildFile
Expand Down Expand Up @@ -116,4 +118,9 @@ abstract class GradleProjectSdkResolverTestCase : GradleImportingTestCase() {
withJavaPlugin()
}
}

fun createDaemonJvmPropertiesFile(sdk: Sdk) {
val version = JavaVersion.tryParse(sdk.versionString!!)
VfsTestUtil.createFile(projectRoot, "gradle/gradle-daemon-jvm.properties", "toolchainVersion=$version")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.jetbrains.plugins.gradle.service.execution

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.externalSystem.model.ProjectSystemId
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkException
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkProvider
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkUtil.USE_INTERNAL_JAVA
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkUtil.USE_JAVA_HOME
import com.intellij.openapi.externalSystem.service.internal.AbstractExternalSystemTask
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ui.configuration.SdkLookupProvider
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.testFramework.VfsTestUtil
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.settings.GradleSettings

class LocalGradleExecutionAwareTest : LightPlatformTestCase() {

fun `test Project without linked projectSettings When prepare JVM execution Then any validation is skipped`() {
prepareJvmForExecution().run {
assertNull(this)
}
}

fun `test Given project using valid JAVA_INTERNAL When prepare JVM execution Then SDK info is returned as resolved`() {
GradleSettings.getInstance(project).linkedProjectsSettings = listOf(GradleProjectSettings().apply {
this.externalProjectPath = project.basePath
this.gradleJvm = USE_INTERNAL_JAVA
})
(prepareJvmForExecution() as SdkLookupProvider.SdkInfo.Resolved).run {
assertEquals(ExternalSystemJdkProvider.getInstance().getInternalJdk().name, name)
assertEquals(ExternalSystemJdkProvider.getInstance().getInternalJdk().homePath, homePath)
}
}

fun `test Given project using Daemon toolchain When prepare JVM execution Then throws expected exception`() {
GradleSettings.getInstance(project).linkedProjectsSettings = listOf(GradleProjectSettings().apply {
this.externalProjectPath = project.basePath
this.gradleJvm = "Invalid jdk.table entry"
})

assertThrows(ExternalSystemJdkException::class.java) {
ApplicationManager.getApplication().executeOnPooledThread {
prepareJvmForExecution()
}
}
}

fun `test Given project using Daemon toolchain When prepare JVM execution Then any validation is skipped`() {
VfsTestUtil.createFile(project.baseDir, "gradle/gradle-daemon-jvm.properties", "toolchainVersion=17")
GradleSettings.getInstance(project).linkedProjectsSettings = listOf(GradleProjectSettings().apply {
this.externalProjectPath = project.basePath
this.gradleJvm = USE_JAVA_HOME
})
prepareJvmForExecution().run {
assertNull(this)
}
}

private fun prepareJvmForExecution() =
LocalGradleExecutionAware().prepareJvmForExecution(DummyTask(project), project.basePath!!, DummyTaskNotificationListener(), project)

private class DummyTask(project: Project) : AbstractExternalSystemTask(
ProjectSystemId.IDE, ExternalSystemTaskType.EXECUTE_TASK, project, ""
) {
override fun doCancel(): Boolean = true

override fun doExecute() {}
}

private class DummyTaskNotificationListener : ExternalSystemTaskNotificationListener {
override fun onStart(id: ExternalSystemTaskId, workingDir: String?) {}

override fun onEnd(id: ExternalSystemTaskId) {}
}
}

0 comments on commit 8aa741b

Please sign in to comment.