From 1874b911e7d087f7f45c77ca49468b39339c7fec Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Sat, 30 Sep 2023 22:02:58 +0530 Subject: [PATCH] fix(tooling-api): avoid recreating ProjectConnection multiple times Also, the TaskExecutionMessage now only accepts the tasks to run, not the project path and the Gradle distribution params --- .../services/builder/GradleBuildService.kt | 14 +---- .../projects/builder/BuildService.kt | 17 ------ .../tooling/impl/ToolingApiServerImpl.kt | 57 ++++++++----------- .../api/messages/TaskExecutionMessage.kt | 2 - 4 files changed, 26 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt b/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt index 9315e12d9..7a4dd872f 100644 --- a/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt +++ b/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.kt @@ -348,19 +348,7 @@ class GradleBuildService : Service(), BuildService, IToolingApiClient, override fun executeTasks(vararg tasks: String): CompletableFuture { checkServerStarted() - val message = TaskExecutionMessage(null, listOf(*tasks), - gradleDistributionParams) - return performBuildTasks( - server!!.executeTasks(message)) - } - - override fun executeProjectTasks( - projectPath: String, - vararg tasks: String - ): CompletableFuture { - checkServerStarted() - val message = TaskExecutionMessage(projectPath, listOf(*tasks), - gradleDistributionParams) + val message = TaskExecutionMessage(listOf(*tasks)) return performBuildTasks( server!!.executeTasks(message)) } diff --git a/subprojects/projects/src/main/java/com/itsaky/androidide/projects/builder/BuildService.kt b/subprojects/projects/src/main/java/com/itsaky/androidide/projects/builder/BuildService.kt index caa86fa42..a5a4c2c0e 100644 --- a/subprojects/projects/src/main/java/com/itsaky/androidide/projects/builder/BuildService.kt +++ b/subprojects/projects/src/main/java/com/itsaky/androidide/projects/builder/BuildService.kt @@ -68,26 +68,9 @@ interface BuildService { * then it will be executed in the root project directory. * @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result * contains a list of tasks that were executed and the result of the whole execution. - * @see BuildService.executeProjectTasks */ fun executeTasks(vararg tasks: String): CompletableFuture - /** - * Execute the given tasks of the given project. - * - * @param projectPath The path of the project. All the tasks will be executed in this project. - * @param tasks The tasks to execute. These may or may not be fully qualified names of the - * project. If the task name is not fully qualified, then it will be executed in the given - * project path. For example, if the project path is ':app' and the task is 'assembleDebug', - * then, ':app:assembleDebug' task will be executed. - * @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result - * contains a list of tasks that were executed and the result of the whole execution. - */ - fun executeProjectTasks( - projectPath: String, - vararg tasks: String, - ): CompletableFuture - /** Cancel any running build. */ fun cancelCurrentBuild(): CompletableFuture } diff --git a/subprojects/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/ToolingApiServerImpl.kt b/subprojects/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/ToolingApiServerImpl.kt index b0508a6b3..85b1f237d 100644 --- a/subprojects/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/ToolingApiServerImpl.kt +++ b/subprojects/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/ToolingApiServerImpl.kt @@ -39,7 +39,6 @@ import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult.Fai import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult.Failure.UNSUPPORTED_BUILD_ARGUMENT import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult.Failure.UNSUPPORTED_CONFIGURATION import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult.Failure.UNSUPPORTED_GRADLE_VERSION -import com.itsaky.androidide.tooling.api.models.params.StringParameter import com.itsaky.androidide.tooling.impl.internal.ProjectImpl import com.itsaky.androidide.tooling.impl.sync.ModelBuilderException import com.itsaky.androidide.tooling.impl.sync.RootModelBuilder @@ -69,6 +68,7 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) : private var initialized = false private var client: IToolingApiClient? = null private var connector: GradleConnector? = null + private var connection: ProjectConnection? = null private var lastInitParams: InitializeProjectParams? = null private var buildCancellationToken: CancellationTokenSource? = null private val log = ILogger.newInstance(javaClass.simpleName) @@ -85,9 +85,11 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) : } val stopWatch = StopWatch("Connection to project") + val isReinitializing = connector != null && connection != null && params == lastInitParams - if (connector != null && params == lastInitParams) { - log.info("Project is being reinitialized. Reusing connector instance...") + if (isReinitializing) { + log.info("Project is being reinitialized") + log.info("Reusing connector instance...") } else { // a new project is being initialized // or the project is being initialized with different parameters @@ -100,13 +102,22 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) : lastInitParams = params - checkNotNull(connector) { + val connector = checkNotNull(connector) { "Unable to create gradle connector for project directory: ${params.directory}" } notifyBeforeBuild(BuildInfo(emptyList())) - val connection = this.connector!!.connect() + if (isReinitializing) { + log.info("Reusing project connection...") + } else { + connection = connector.connect() + } + + val connection = checkNotNull(this.connection) { + "Unable to create project connection for project directory: ${params.directory}" + } + stopWatch.lapFromLast("Project connection established") val project = try { @@ -115,8 +126,6 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) : impl } catch (err: Throwable) { throw err - } finally { - connection.close() } stopWatch.lapFromLast("Project read successful") @@ -152,26 +161,13 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) : assertProjectInitialized() log.debug("Received request to run tasks.", message) + Main.checkGradleWrapper() - var projectPath = message.projectPath - if (projectPath == null) { - projectPath = project.rootProjectPath + val connection = checkNotNull(this.connection) { + "ProjectConnection has not been initialized. Cannot execute tasks." } - checkNotNull(projectPath) { - "Unable to determine root project path" - } - - val project = this.project.run { - selectProject(StringParameter(projectPath)).get() - asGradleProject() - } - - this.connector!!.forProjectDirectory(project.getMetadata().get().projectDir) - setupConnectorForGradleInstallation(this.connector!!, message.gradleDistribution) - - val connection = this.connector!!.connect() val builder = connection.newBuild() // System.in and System.out are used for communication between this server and the @@ -228,21 +224,15 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) : } private fun notifyBuildFailure(tasks: List) { - if (client != null) { - client!!.onBuildFailed(BuildResult((tasks))) - } + client?.onBuildFailed(BuildResult((tasks))) } private fun notifyBuildSuccess(tasks: List) { - if (client != null) { - client!!.onBuildSuccessful(BuildResult(tasks)) - } + client?.onBuildSuccessful(BuildResult(tasks)) } private fun notifyBeforeBuild(buildInfo: BuildInfo) { - if (client != null) { - client!!.prepareBuild(buildInfo) - } + client?.prepareBuild(buildInfo) } override fun cancelCurrentBuild(): CompletableFuture { @@ -268,12 +258,15 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) : override fun shutdown(): CompletableFuture { return CompletableFuture.runAsync { + connection?.close() connector?.disconnect() Main.future?.cancel(true) + this.connection = null this.connector = null this.client = null this.buildCancellationToken = null + this.lastInitParams = null Main.future = null Main.client = null diff --git a/subprojects/tooling-api/src/main/java/com/itsaky/androidide/tooling/api/messages/TaskExecutionMessage.kt b/subprojects/tooling-api/src/main/java/com/itsaky/androidide/tooling/api/messages/TaskExecutionMessage.kt index d12c42839..eb86d3ab4 100644 --- a/subprojects/tooling-api/src/main/java/com/itsaky/androidide/tooling/api/messages/TaskExecutionMessage.kt +++ b/subprojects/tooling-api/src/main/java/com/itsaky/androidide/tooling/api/messages/TaskExecutionMessage.kt @@ -22,7 +22,5 @@ package com.itsaky.androidide.tooling.api.messages * @author Akash Yadav */ data class TaskExecutionMessage( - val projectPath: String?, val tasks: List, - val gradleDistribution: GradleDistributionParams = GradleDistributionParams.WRAPPER )