diff --git a/plugins/gradle/java/src/service/project/wizard/AbstractGradleModuleBuilder.java b/plugins/gradle/java/src/service/project/wizard/AbstractGradleModuleBuilder.java index 622c57e0d05c..0858597e92cd 100644 --- a/plugins/gradle/java/src/service/project/wizard/AbstractGradleModuleBuilder.java +++ b/plugins/gradle/java/src/service/project/wizard/AbstractGradleModuleBuilder.java @@ -57,9 +57,11 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder; import org.jetbrains.plugins.gradle.frameworkSupport.KotlinBuildScriptDataBuilder; import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData; +import org.jetbrains.plugins.gradle.service.execution.GradleExecutionUtil; import org.jetbrains.plugins.gradle.settings.DistributionType; import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; import org.jetbrains.plugins.gradle.util.GradleConstants; +import org.jetbrains.plugins.gradle.util.GradleJvmResolutionUtil; import org.jetbrains.plugins.gradle.util.GradleJvmValidationUtil; import java.io.File; @@ -207,6 +209,8 @@ public abstract class AbstractGradleModuleBuilder extends AbstractExternalModule VirtualFile buildScriptFile = createAndConfigureBuildScriptFile(module); + FileDocumentManager.getInstance().saveAllDocuments(); + // it will be set later in any case, but save is called immediately after project creation, so, to ensure that it will be properly saved as external system module ExternalSystemModulePropertyManager modulePropertyManager = ExternalSystemModulePropertyManager.getInstance(module); modulePropertyManager.setExternalId(GradleConstants.SYSTEM_ID); @@ -214,9 +218,12 @@ public abstract class AbstractGradleModuleBuilder extends AbstractExternalModule modulePropertyManager.setRootProjectPath(rootProjectPath); modulePropertyManager.setLinkedProjectPath(rootProjectPath); - final Project project = module.getProject(); - FileDocumentManager.getInstance().saveAllDocuments(); - if (myParentProject == null) setupAndLinkGradleProject(project); + Project project = module.getProject(); + + GradleVersion gradleVersion = suggestGradleVersion(project); + if (myParentProject == null) { + setupAndLinkGradleProject(project, gradleVersion); + } if (myWizardContext.isCreatingNewProject()) { project.putUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT, Boolean.TRUE); // Needed to ignore postponed project refresh @@ -227,25 +234,49 @@ public abstract class AbstractGradleModuleBuilder extends AbstractExternalModule ApplicationManager.getApplication().invokeLater(() -> { if (myWizardContext.isCreatingNewProject()) { // update external projects data to be able to add child modules before the initial import finish - ImportSpecBuilder previewSpec = new ImportSpecBuilder(project, GradleConstants.SYSTEM_ID); - previewSpec.usePreviewMode(); - previewSpec.use(MODAL_SYNC); - previewSpec.callback(new ConfigureGradleModuleCallback(previewSpec)); - ExternalSystemUtil.refreshProject(rootProjectPath, previewSpec); + loadPreviewProject(project); } - ImportSpecBuilder importSpec = new ImportSpecBuilder(project, GradleConstants.SYSTEM_ID); - importSpec.createDirectoriesForEmptyContentRoots(); - importSpec.callback(new ConfigureGradleModuleCallback(importSpec)); - ExternalSystemUtil.refreshProject(rootProjectPath, importSpec); openBuildScriptFile(project, buildScriptFile); + if (myParentProject == null) { + createWrapper(project, gradleVersion, () -> { + reloadProject(project); + }); + } + else { + reloadProject(project); + } }, ModalityState.NON_MODAL, project.getDisposed()); } - private void setupAndLinkGradleProject(@NotNull Project project) { + private void setupAndLinkGradleProject(@NotNull Project project, @NotNull GradleVersion gradleVersion) { GradleProjectSettings projectSettings = getExternalProjectSettings(); - setupGradleSettings(projectSettings, rootProjectPath, project); + setupGradleSettings(project, projectSettings, rootProjectPath, gradleVersion); getSystemSettings(project).linkProject(projectSettings); - GradleJvmValidationUtil.validateJavaHome(project, rootProjectPath, projectSettings.resolveGradleVersion()); + GradleJvmValidationUtil.validateJavaHome(project, rootProjectPath, gradleVersion); + } + + private void loadPreviewProject(@NotNull Project project) { + ImportSpecBuilder previewSpec = new ImportSpecBuilder(project, GradleConstants.SYSTEM_ID); + previewSpec.usePreviewMode(); + previewSpec.use(MODAL_SYNC); + previewSpec.callback(new ConfigureGradleModuleCallback(previewSpec)); + ExternalSystemUtil.refreshProject(rootProjectPath, previewSpec); + } + + private void reloadProject(@NotNull Project project) { + ImportSpecBuilder importSpec = new ImportSpecBuilder(project, GradleConstants.SYSTEM_ID); + importSpec.createDirectoriesForEmptyContentRoots(); + importSpec.callback(new ConfigureGradleModuleCallback(importSpec)); + ExternalSystemUtil.refreshProject(rootProjectPath, importSpec); + } + + private void createWrapper(@NotNull Project project, @NotNull GradleVersion gradleVersion, @NotNull Runnable callback) { + GradleExecutionUtil.ensureInstalledWrapper(project, rootProjectPath, gradleVersion, callback); + } + + private static @NotNull GradleVersion suggestGradleVersion(@NotNull Project project) { + GradleVersion gradleVersion = GradleJvmResolutionUtil.suggestGradleVersion(project); + return gradleVersion == null ? GradleVersion.current() : gradleVersion; } private static AbstractExternalSystemSettings getSystemSettings(@NotNull Project project) { diff --git a/plugins/gradle/resources/messages/GradleBundle.properties b/plugins/gradle/resources/messages/GradleBundle.properties index 84bcc99be474..1058a36709ac 100644 --- a/plugins/gradle/resources/messages/GradleBundle.properties +++ b/plugins/gradle/resources/messages/GradleBundle.properties @@ -162,3 +162,5 @@ gradle.tasks.annotations.title=Resolving known external annotations gradle.tasks.annotations.looking.for=Looking for annotations for {0} compiler.build.messages.gradle.configuration.not.found=Unable to make ''{0}''.\nRelated gradle configuration was not found. "Please, re-import the Gradle project and try again. + +gradle.project.generation.wrapper.progress.title=Generating of Gradle Wrapper diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java index 3afa573b002c..1a76d00a3760 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java @@ -299,6 +299,15 @@ public class GradleExecutionHelper { @NotNull GradleExecutionSettings settings, @NotNull ExternalSystemTaskNotificationListener listener, @NotNull CancellationToken cancellationToken) { + ensureInstalledWrapper(id, projectPath, settings, GradleVersion.current(), listener, cancellationToken); + } + + public void ensureInstalledWrapper(@NotNull ExternalSystemTaskId id, + @NotNull String projectPath, + @NotNull GradleExecutionSettings settings, + @NotNull GradleVersion gradleVersion, + @NotNull ExternalSystemTaskNotificationListener listener, + @NotNull CancellationToken cancellationToken) { if (!settings.getDistributionType().isWrapped()) return; @@ -329,6 +338,7 @@ public class GradleExecutionHelper { " wrapper.jarFile = new File('" + StringUtil.escapeBackSlashes(jarFile.getCanonicalPath()) + "')", " wrapper.scriptFile = new File('" + StringUtil.escapeBackSlashes(scriptFile.getCanonicalPath()) + "')", " }", + " wrapper.gradleVersion = '" + gradleVersion.getVersion() + "'", " wrapper.doLast {", " new File('" + StringUtil.escapeBackSlashes(pathToProperties.getCanonicalPath()) + "').write wrapper.propertiesFile.getCanonicalPath()", " }", diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionUtil.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionUtil.kt new file mode 100644 index 000000000000..91a6771e3149 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionUtil.kt @@ -0,0 +1,114 @@ +// 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. +@file:JvmName("GradleExecutionUtil") + +package org.jetbrains.plugins.gradle.service.execution + +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType.EXECUTE_TASK +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkProvider +import com.intellij.openapi.externalSystem.service.internal.AbstractExternalSystemTask +import com.intellij.openapi.externalSystem.service.remote.ExternalSystemProgressNotificationManagerImpl +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.Task +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.io.FileUtil +import org.gradle.tooling.GradleConnector +import org.gradle.util.GradleVersion +import org.jetbrains.plugins.gradle.service.GradleInstallationManager +import org.jetbrains.plugins.gradle.settings.DistributionType +import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings +import org.jetbrains.plugins.gradle.settings.GradleSettings +import org.jetbrains.plugins.gradle.util.GradleBundle +import org.jetbrains.plugins.gradle.util.GradleConstants.SYSTEM_ID +import org.jetbrains.plugins.gradle.util.GradleUtil + + +fun ensureInstalledWrapper(project: Project, externalProjectPath: String, gradleVersion: GradleVersion, callback: Runnable) { + val ensureInstalledWrapperTask = EnsureInstalledWrapperExecutionTask(project, externalProjectPath, gradleVersion) + val title = GradleBundle.message("gradle.project.generation.wrapper.progress.title") + val task = object : Task.Backgroundable(project, title, true) { + override fun run(indicator: ProgressIndicator) { + val listener = object : ExternalSystemTaskNotificationListenerAdapter() { + override fun onEnd(id: ExternalSystemTaskId) = callback.run() + } + ensureInstalledWrapperTask.execute(indicator, listener) + } + } + task.queue() +} + +private class EnsureInstalledWrapperExecutionTask( + project: Project, + externalProjectPath: String, + private val gradleVersion: GradleVersion +) : AbstractExternalSystemTask(SYSTEM_ID, EXECUTE_TASK, project, externalProjectPath) { + + private val progressNotificationManager = ExternalSystemProgressNotificationManagerImpl.getInstanceImpl() + private val newCancellationTokenSource = GradleConnector.newCancellationTokenSource() + + private fun createExecutionSettings(): GradleExecutionSettings { + val settings = GradleSettings.getInstance(ideProject) + val executionSettings = GradleExecutionSettings( + getGradleHome(), + settings.serviceDirectoryPath, + getDistributionType(), + settings.gradleVmOptions, + settings.isOfflineWork + ) + val jdkProvider = ExternalSystemJdkProvider.getInstance() + executionSettings.javaHome = jdkProvider.internalJdk.homePath + return executionSettings + } + + private fun getGradleHome(): String? { + val installationManager = GradleInstallationManager.getInstance() + val gradleHome = installationManager.getGradleHome(ideProject, externalProjectPath) + return FileUtil.toCanonicalPath(gradleHome?.path) + } + + private fun getDistributionType(): DistributionType { + val settings = GradleSettings.getInstance(ideProject) + val projectSettings = settings.getLinkedProjectSettings(externalProjectPath) + return when { + projectSettings != null -> projectSettings.distributionType ?: DistributionType.LOCAL + GradleUtil.isGradleDefaultWrapperFilesExist(externalProjectPath) -> DistributionType.DEFAULT_WRAPPED + else -> DistributionType.BUNDLED + } + } + + private fun ensureInstalledWrapper(listener: ExternalSystemTaskNotificationListener) { + GradleExecutionHelper().ensureInstalledWrapper( + id, + externalProjectPath, + createExecutionSettings(), + gradleVersion, + listener, + newCancellationTokenSource.token() + ) + } + + override fun doExecute() { + val progressNotificationListener = wrapWithListener(progressNotificationManager) + try { + progressNotificationManager.onStart(id, externalProjectPath) + ensureInstalledWrapper(progressNotificationListener) + progressNotificationManager.onSuccess(id) + } + catch (e: Exception) { + progressNotificationManager.onFailure(id, e) + throw e + } + finally { + progressNotificationManager.onEnd(id) + } + } + + override fun doCancel(): Boolean { + progressNotificationManager.beforeCancel(id) + newCancellationTokenSource.cancel() + progressNotificationManager.onCancel(id) + return true + } +} \ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleOpenProjectProvider.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleOpenProjectProvider.kt index b5229d18641e..f06f21df27e9 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleOpenProjectProvider.kt +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleOpenProjectProvider.kt @@ -21,6 +21,7 @@ import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.text.nullize +import org.gradle.util.GradleVersion import org.jetbrains.plugins.gradle.service.GradleInstallationManager import org.jetbrains.plugins.gradle.settings.DistributionType import org.jetbrains.plugins.gradle.settings.GradleProjectSettings @@ -37,9 +38,10 @@ internal class GradleOpenProjectProvider : AbstractOpenProjectProvider() { override fun linkAndRefreshProject(projectDirectory: String, project: Project) { val gradleProjectSettings = GradleProjectSettings() - setupGradleSettings(gradleProjectSettings, projectDirectory, project) + val gradleVersion = gradleProjectSettings.resolveGradleVersion() + setupGradleSettings(project, gradleProjectSettings, projectDirectory, gradleVersion) attachGradleProjectAndRefresh(gradleProjectSettings, project) - validateJavaHome(project, projectDirectory, gradleProjectSettings.resolveGradleVersion()) + validateJavaHome(project, projectDirectory, gradleVersion) } override fun openProject(projectFile: VirtualFile, projectToClose: Project?, forceOpenInNewFrame: Boolean): Project? { @@ -65,10 +67,10 @@ internal class GradleOpenProjectProvider : AbstractOpenProjectProvider() { .callback(createFinalImportCallback(project, externalProjectPath))) } - fun setupGradleSettings(settings: GradleProjectSettings, projectDirectory: String, project: Project) { + fun setupGradleSettings(project: Project, settings: GradleProjectSettings, projectDirectory: String, gradleVersion: GradleVersion) { GradleSettings.getInstance(project).setupGradleSettings() settings.setupGradleProjectSettings(projectDirectory) - setupGradleJvm(project, settings, projectDirectory) + setupGradleJvm(project, settings, projectDirectory, gradleVersion) } private fun GradleSettings.setupGradleSettings() { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleProjectImportUtil.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleProjectImportUtil.kt index cd85483b379e..49e71f29da7f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleProjectImportUtil.kt +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/open/GradleProjectImportUtil.kt @@ -10,6 +10,7 @@ import com.intellij.openapi.ui.ValidationInfo import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile +import org.gradle.util.GradleVersion import org.jetbrains.annotations.ApiStatus import org.jetbrains.plugins.gradle.settings.GradleProjectSettings import org.jetbrains.plugins.gradle.util.GradleConstants @@ -44,8 +45,8 @@ fun linkAndRefreshGradleProject(projectFilePath: String, project: Project) { GradleOpenProjectProvider().linkToExistingProject(projectFile, project) } -fun setupGradleSettings(settings: GradleProjectSettings, projectDirectory: String, project: Project) = - GradleOpenProjectProvider().setupGradleSettings(settings, projectDirectory, project) +fun setupGradleSettings(project: Project, settings: GradleProjectSettings, projectDirectory: String, gradleVersion: GradleVersion) = + GradleOpenProjectProvider().setupGradleSettings(project, settings, projectDirectory, gradleVersion) private fun validateGradleProject(projectFilePath: String, project: Project): ValidationInfo? { val systemSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleJvmResolutionUtil.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleJvmResolutionUtil.kt index 626aba0009a9..62c84cead117 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleJvmResolutionUtil.kt +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleJvmResolutionUtil.kt @@ -5,13 +5,16 @@ package org.jetbrains.plugins.gradle.util import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkProvider import com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkUtil import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.JdkUtil import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.roots.ui.configuration.SdkLookupProvider import com.intellij.openapi.roots.ui.configuration.SdkLookupProvider.Id +import com.intellij.util.lang.JavaVersion import org.gradle.util.GradleVersion import org.jetbrains.annotations.ApiStatus import org.jetbrains.plugins.gradle.settings.GradleProjectSettings @@ -23,10 +26,6 @@ private data class GradleJvmProviderId(val projectSettings: GradleProjectSetting fun getGradleJvmLookupProvider(project: Project, projectSettings: GradleProjectSettings) = SdkLookupProvider.getInstance(project, GradleJvmProviderId(projectSettings)) -fun setupGradleJvm(project: Project, projectSettings: GradleProjectSettings, externalProjectPath: String) { - setupGradleJvm(project, projectSettings, externalProjectPath, projectSettings.resolveGradleVersion()) -} - fun setupGradleJvm(project: Project, projectSettings: GradleProjectSettings, externalProjectPath: String, gradleVersion: GradleVersion) { with(GradleJvmResolutionContext(project, externalProjectPath, gradleVersion)) { projectSettings.gradleJvm = findGradleJvm() @@ -73,21 +72,42 @@ fun updateGradleJvm(project: Project, externalProjectPath: String) { val settings = GradleSettings.getInstance(project) val projectSettings = settings.getLinkedProjectSettings(externalProjectPath) ?: return val gradleJvm = projectSettings.gradleJvm ?: return - val gradleVersion = projectSettings.resolveGradleVersion() - with(GradleJvmResolutionContext(project, externalProjectPath, gradleVersion)) { - val projectSdk = projectSdk ?: return - if (projectSdk.name != gradleJvm) return - projectSettings.gradleJvm = ExternalSystemJdkUtil.USE_PROJECT_JDK + val projectRootManager = ProjectRootManager.getInstance(project) + val projectSdk = projectRootManager.projectSdk ?: return + if (projectSdk.name != gradleJvm) return + projectSettings.gradleJvm = ExternalSystemJdkUtil.USE_PROJECT_JDK +} + +fun suggestGradleVersion(project: Project): GradleVersion? { + val gradleVersion = findGradleVersion(project) + if (gradleVersion != null) return gradleVersion + val projectJdk = resolveProjectJdk(project) ?: return null + if (!ExternalSystemJdkUtil.isValidJdk(projectJdk)) return null + val javaVersion = JavaVersion.tryParse(projectJdk.versionString) ?: return null + return suggestGradleVersion(javaVersion) +} + +private fun suggestGradleVersion(javaVersion: JavaVersion): GradleVersion? { + return when (javaVersion.feature) { + in 8..14 -> GradleVersion.version("6.3") + 7 -> GradleVersion.version("4.1") + 6 -> GradleVersion.version("3.0") + else -> null } } +private fun findGradleVersion(project: Project): GradleVersion? { + val settings = GradleSettings.getInstance(project) + return settings.linkedProjectsSettings.asSequence() + .mapNotNull { it.resolveGradleVersion() } + .firstOrNull() +} + private class GradleJvmResolutionContext( val project: Project, val externalProjectPath: String, val gradleVersion: GradleVersion -) { - val projectSdk: Sdk? by lazy { ProjectRootManager.getInstance(project).projectSdk } -} +) private fun GradleJvmResolutionContext.canUseGradleJavaHomeJdk(): Boolean { val properties = getGradleProperties(externalProjectPath) @@ -110,11 +130,17 @@ private fun GradleJvmResolutionContext.findGradleJvm(): String? { } private fun GradleJvmResolutionContext.canUseProjectSdk(): Boolean { - val projectSdk = projectSdk ?: return false - val resolvedProjectSdk = ExternalSystemJdkUtil.resolveDependentJdk(projectSdk) - return ExternalSystemJdkUtil.isValidJdk(resolvedProjectSdk) + val projectJdk = resolveProjectJdk(project) ?: return false + return ExternalSystemJdkUtil.isValidJdk(projectJdk) } +private fun resolveProjectJdk(project: Project): Sdk? { + val projectRootManager = ProjectRootManager.getInstance(project) + val projectSdk = projectRootManager.projectSdk ?: return null + return ExternalSystemJdkUtil.resolveDependentJdk(projectSdk) +} + + private fun findRegisteredSdk(sdk: Sdk): Sdk? = runReadAction { val projectJdkTable = ProjectJdkTable.getInstance() projectJdkTable.findJdk(sdk.name, sdk.sdkType.name)