mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix: add ability to use custom Gradle dist version in tooling API
This commit is contained in:
+1
-3
@@ -46,9 +46,7 @@ class ModuleProjectTest {
|
||||
|
||||
@Test
|
||||
fun test() {
|
||||
val (server, project) = ToolingApiTestLauncher().launchServer()
|
||||
val result = server.initialize(InitializeProjectParams(FileProvider.testProjectRoot().pathString))
|
||||
.get()
|
||||
val (_, project, result) = ToolingApiTestLauncher().launchServer()
|
||||
assertThat(result?.isSuccessful).isTrue()
|
||||
|
||||
Lookup.getDefault().register(BuildService.KEY_PROJECT_PROXY, project)
|
||||
|
||||
+25
-14
@@ -20,6 +20,8 @@ package com.itsaky.androidide.tooling.impl
|
||||
import com.itsaky.androidide.tooling.api.IProject
|
||||
import com.itsaky.androidide.tooling.api.IToolingApiClient
|
||||
import com.itsaky.androidide.tooling.api.IToolingApiServer
|
||||
import com.itsaky.androidide.tooling.api.messages.GradleDistributionParams
|
||||
import com.itsaky.androidide.tooling.api.messages.GradleDistributionType
|
||||
import com.itsaky.androidide.tooling.api.messages.InitializeProjectParams
|
||||
import com.itsaky.androidide.tooling.api.messages.TaskExecutionMessage
|
||||
import com.itsaky.androidide.tooling.api.messages.result.BuildCancellationRequestResult
|
||||
@@ -86,7 +88,7 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
log.debug("Got initialize request", params)
|
||||
val stopWatch = StopWatch("Connection to project")
|
||||
this.connector = GradleConnector.newConnector().forProjectDirectory(File(params.directory))
|
||||
setupConnectorForGradleInstallation(this.connector!!, params.gradleInstallation)
|
||||
setupConnectorForGradleInstallation(this.connector!!, params.gradleDistribution)
|
||||
stopWatch.lap("Connector created")
|
||||
|
||||
if (this.connector == null) {
|
||||
@@ -155,7 +157,7 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
}
|
||||
|
||||
this.connector!!.forProjectDirectory(project.getMetadata().get().projectDir)
|
||||
setupConnectorForGradleInstallation(this.connector!!, message.gradleInstallation)
|
||||
setupConnectorForGradleInstallation(this.connector!!, message.gradleDistribution)
|
||||
|
||||
val connection = this.connector!!.connect()
|
||||
val builder = connection.newBuild()
|
||||
@@ -188,20 +190,29 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
|
||||
private fun setupConnectorForGradleInstallation(
|
||||
connector: GradleConnector,
|
||||
gradleDistribution: String?
|
||||
params: GradleDistributionParams
|
||||
) {
|
||||
if (gradleDistribution.isNullOrBlank()) {
|
||||
log.info("Using Gradle wrapper for build...")
|
||||
return
|
||||
}
|
||||
val file = File(gradleDistribution)
|
||||
if (!file.exists() || !file.isDirectory) {
|
||||
log.error("Specified Gradle installation does not exist:", gradleDistribution)
|
||||
return
|
||||
}
|
||||
when (params.type) {
|
||||
GradleDistributionType.GRADLE_WRAPPER -> {
|
||||
log.info("Using Gradle wrapper for build...")
|
||||
}
|
||||
|
||||
log.info("Using Gradle installation:", file.canonicalPath)
|
||||
connector.useInstallation(file)
|
||||
GradleDistributionType.GRADLE_INSTALLATION -> {
|
||||
val file = File(params.value)
|
||||
if (!file.exists() || !file.isDirectory) {
|
||||
log.error("Specified Gradle installation does not exist:", params)
|
||||
return
|
||||
}
|
||||
|
||||
log.info("Using Gradle installation:", file.canonicalPath)
|
||||
connector.useInstallation(file)
|
||||
}
|
||||
|
||||
GradleDistributionType.GRADLE_VERSION -> {
|
||||
log.info("Using Gradle version '${params.value}'")
|
||||
connector.useGradleVersion(params.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyBuildFailure(tasks: List<String>) {
|
||||
|
||||
+29
-32
@@ -49,8 +49,8 @@ class MultiModuleAndroidProjectTest {
|
||||
|
||||
@Test
|
||||
fun `test simple multi module project initialization`() {
|
||||
val (server, project) = ToolingApiTestLauncher().launchServer()
|
||||
server.initializeTestProject()
|
||||
val (server, project, result) = ToolingApiTestLauncher().launchServer()
|
||||
assertThat(result?.isSuccessful).isTrue()
|
||||
doAssertions(project, server)
|
||||
}
|
||||
|
||||
@@ -200,10 +200,9 @@ class MultiModuleAndroidProjectTest {
|
||||
for ((agpVersion, gradleVersion) in versions) {
|
||||
client.agpVersion = agpVersion
|
||||
client.gradleVersion = gradleVersion
|
||||
val (server, project) = ToolingApiTestLauncher().launchServer(client = client)
|
||||
server.initializeTestProject()
|
||||
val (server, project, result) = ToolingApiTestLauncher().launchServer(client = client)
|
||||
assertThat(result?.isSuccessful).isTrue()
|
||||
doAssertions(project = project, server = server)
|
||||
FileProvider.testProjectRoot().resolve(MultiVersionTestClient.buildFile).deleteExisting()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,36 +210,38 @@ class MultiModuleAndroidProjectTest {
|
||||
@Test
|
||||
@Throws(CIOnlyException::class)
|
||||
fun `test CI-only latest tested AGP version warning`() {
|
||||
val log = CollectingLogger()
|
||||
val agpVersion = "8.1.1"
|
||||
val client = MultiVersionTestClient(agpVersion = agpVersion, gradleVersion = "8.2", log = log)
|
||||
val (server, _) = ToolingApiTestLauncher().launchServer(client = client, log = log)
|
||||
val result = server.initializeTestProject()
|
||||
val output = log.toString()
|
||||
ciOnlyTest {
|
||||
val log = CollectingLogger()
|
||||
val agpVersion = "8.1.1"
|
||||
val client = MultiVersionTestClient(agpVersion = agpVersion, gradleVersion = "8.1", log = log)
|
||||
val (_, _, result) = ToolingApiTestLauncher().launchServer(client = client, log = log)
|
||||
val output = log.toString()
|
||||
|
||||
if (result?.isSuccessful != true) {
|
||||
// print the output if the initialization fails
|
||||
println(output)
|
||||
if (result?.isSuccessful != true) {
|
||||
// print the output if the initialization fails
|
||||
println(output)
|
||||
}
|
||||
|
||||
assertThat(result?.isSuccessful).isTrue()
|
||||
assertThat(output).contains(
|
||||
"You are using Android Gradle Plugin version that has not been tested with AndroidIDE.")
|
||||
}
|
||||
|
||||
assertThat(result?.isSuccessful).isTrue()
|
||||
assertThat(output).contains(
|
||||
"You are using Android Gradle Plugin version that has not been tested with AndroidIDE.")
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(CIOnlyException::class)
|
||||
fun `test CI-only minimum AGP version failure`() {
|
||||
val log = CollectingLogger()
|
||||
val agpVersion = "7.1.0"
|
||||
val client = MultiVersionTestClient(agpVersion = agpVersion, log = log)
|
||||
val (server, _) = ToolingApiTestLauncher().launchServer(client = client, log = log)
|
||||
val result = server.initializeTestProject()
|
||||
assertThat(result?.isSuccessful).isFalse()
|
||||
ciOnlyTest {
|
||||
val log = CollectingLogger()
|
||||
val agpVersion = "7.1.0"
|
||||
val client = MultiVersionTestClient(agpVersion = agpVersion, gradleVersion = "7.2", log = log)
|
||||
val (_, _, result) = ToolingApiTestLauncher().launchServer(client = client, log = log)
|
||||
assertThat(result?.isSuccessful).isFalse()
|
||||
|
||||
val output = log.toString()
|
||||
assertThat(output).contains(
|
||||
"Android Gradle Plugin version $agpVersion is not supported by AndroidIDE.")
|
||||
val output = log.toString()
|
||||
assertThat(output).contains(
|
||||
"Android Gradle Plugin version $agpVersion is not supported by AndroidIDE.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ciOnlyTest(test: () -> Unit) {
|
||||
@@ -264,11 +265,7 @@ class MultiModuleAndroidProjectTest {
|
||||
return System.getenv("TEST_TOOLING_API_IMPL").let { it == "true" }
|
||||
}
|
||||
|
||||
private fun IToolingApiServer.initializeTestProject(): InitializeResult? {
|
||||
return initialize(InitializeProjectParams(FileProvider.testProjectRoot().pathString)).get()
|
||||
}
|
||||
|
||||
internal class CollectingLogger() : ILogger(CollectingLogger::class.simpleName) {
|
||||
internal class CollectingLogger : ILogger(CollectingLogger::class.simpleName) {
|
||||
|
||||
private val string = StringBuilder()
|
||||
|
||||
|
||||
+18
-13
@@ -21,9 +21,12 @@ import com.itsaky.androidide.models.LogLine
|
||||
import com.itsaky.androidide.tooling.api.IProject
|
||||
import com.itsaky.androidide.tooling.api.IToolingApiClient
|
||||
import com.itsaky.androidide.tooling.api.IToolingApiServer
|
||||
import com.itsaky.androidide.tooling.api.messages.GradleDistributionParams
|
||||
import com.itsaky.androidide.tooling.api.messages.InitializeProjectParams
|
||||
import com.itsaky.androidide.tooling.api.messages.result.BuildInfo
|
||||
import com.itsaky.androidide.tooling.api.messages.result.BuildResult
|
||||
import com.itsaky.androidide.tooling.api.messages.result.GradleWrapperCheckResult
|
||||
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult
|
||||
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher
|
||||
import com.itsaky.androidide.tooling.events.ProgressEvent
|
||||
import com.itsaky.androidide.utils.FileProvider
|
||||
@@ -60,10 +63,16 @@ class ToolingApiTestLauncher {
|
||||
"jdk.compiler" to "com.sun.tools.javac.tree",
|
||||
"jdk.compiler" to "com.sun.tools.javac.util")
|
||||
|
||||
@JvmOverloads
|
||||
fun launchServer(
|
||||
client: IToolingApiClient = MultiVersionTestClient(),
|
||||
projectDir: Path = FileProvider.testProjectRoot(),
|
||||
client: MultiVersionTestClient = MultiVersionTestClient(),
|
||||
initParams: InitializeProjectParams = InitializeProjectParams(
|
||||
projectDir.pathString,
|
||||
GradleDistributionParams.forVersion(client.gradleVersion)
|
||||
),
|
||||
log: ILogger = ILogger.newInstance("BuildOutputLogger")
|
||||
): Pair<IToolingApiServer, IProject> {
|
||||
): Triple<IToolingApiServer, IProject, InitializeResult?> {
|
||||
val builder = ProcessBuilder(createProcessCmd(FileProvider.implModule()
|
||||
.resolve("build/libs/tooling-api-all.jar").pathString))
|
||||
val androidHome = findAndroidHome()
|
||||
@@ -79,7 +88,10 @@ class ToolingApiTestLauncher {
|
||||
|
||||
launcher.startListening()
|
||||
|
||||
return launcher.remoteProxy as IToolingApiServer to launcher.remoteProxy as IProject
|
||||
val server = launcher.remoteProxy as IToolingApiServer
|
||||
val project = launcher.remoteProxy as IProject
|
||||
val result = server.initialize(initParams).get()
|
||||
return Triple(server, project, result)
|
||||
}
|
||||
|
||||
private fun createProcessCmd(jar: String): List<String> {
|
||||
@@ -94,7 +106,7 @@ class ToolingApiTestLauncher {
|
||||
cmd[0] = java.absolutePath
|
||||
}
|
||||
}
|
||||
// cmd.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000")
|
||||
|
||||
for (open in opens) {
|
||||
cmd.add("--add-opens=${open.key}/${open.value}=ALL-UNNAMED")
|
||||
}
|
||||
@@ -123,11 +135,8 @@ class ToolingApiTestLauncher {
|
||||
const val buildFile = "build.gradle"
|
||||
const val buildFileIn = "$buildFile.in"
|
||||
|
||||
const val gradlewProps = "gradle/wrapper/gradle-wrapper.properties"
|
||||
const val gradlewPropsIn = "$gradlewProps.in"
|
||||
|
||||
const val DEFAULT_AGP_VERSION = "7.2.0"
|
||||
const val DEFAULT_GRADLE_VERSION = "7.5.1"
|
||||
const val DEFAULT_GRADLE_VERSION = "7.3.3"
|
||||
|
||||
const val GENERATED_FILE_WARNING =
|
||||
"DO NOT EDIT - Automatically generated file"
|
||||
@@ -150,22 +159,18 @@ class ToolingApiTestLauncher {
|
||||
projectDir.resolve(buildFileIn)
|
||||
.replaceContents(dest = projectDir.resolve(buildFile),
|
||||
candidate = "@@TOOLING_API_TEST_AGP_VERSION@@" to this.agpVersion)
|
||||
|
||||
projectDir.resolve(gradlewPropsIn)
|
||||
.replaceContents(comment = "#", dest = projectDir.resolve(gradlewProps),
|
||||
candidate = "@@GRADLE_VERSION@@" to this.gradleVersion)
|
||||
}
|
||||
|
||||
override fun onBuildSuccessful(result: BuildResult) {
|
||||
onBuildResult(result)
|
||||
}
|
||||
|
||||
override fun onBuildFailed(result: BuildResult) {
|
||||
onBuildResult(result)
|
||||
}
|
||||
|
||||
private fun onBuildResult(result: BuildResult) {
|
||||
projectDir.resolve(buildFile).deleteIfExists()
|
||||
projectDir.resolve(gradlewProps).deleteIfExists()
|
||||
}
|
||||
|
||||
override fun onProgressEvent(event: ProgressEvent) {}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.tooling.api.messages
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Initialization params for Android project/modules.
|
||||
*
|
||||
* @property variantSelections The map of module paths to the name of the variants which should
|
||||
* be fetched/initialized.
|
||||
*/
|
||||
data class AndroidInitializationParams(val variantSelections: Map<String, String>) : Serializable {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Default initialization params. This initializes the Android modules with default values.
|
||||
*/
|
||||
@JvmStatic
|
||||
val DEFAULT = AndroidInitializationParams(emptyMap())
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.tooling.api.messages
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Parameters for specifying the Gradle distribution which should be used during project initialization.
|
||||
*
|
||||
* @property type The type of Gradle distribution.
|
||||
* @property value The value for the distribution type.
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
data class GradleDistributionParams(val type: GradleDistributionType, val value: String) :
|
||||
Serializable {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* [GradleDistributionParams] with type [GRADLE_WRAPPER][GradleDistributionType.GRADLE_WRAPPER].
|
||||
*/
|
||||
@JvmStatic
|
||||
val WRAPPER = GradleDistributionParams(GradleDistributionType.GRADLE_WRAPPER, "")
|
||||
|
||||
/**
|
||||
* Creates [GradleDistributionParams] for the given [distribution path][path].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun forInstallationDir(path: String): GradleDistributionParams {
|
||||
return GradleDistributionParams(GradleDistributionType.GRADLE_INSTALLATION, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates [GradleDistributionParams] for the given [Gradle version][version].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun forVersion(version: String): GradleDistributionParams {
|
||||
return GradleDistributionParams(GradleDistributionType.GRADLE_VERSION, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of Gradle distributions for project initialization.
|
||||
*/
|
||||
enum class GradleDistributionType {
|
||||
|
||||
/**
|
||||
* Initialize the project using the distribution specified in `gradle-wrapper.properties`.
|
||||
*/
|
||||
GRADLE_WRAPPER,
|
||||
|
||||
/**
|
||||
* Initialize the project using a specific Gradle version.
|
||||
*/
|
||||
GRADLE_VERSION,
|
||||
|
||||
/**
|
||||
* Initialize the project using a specific Gradle distribution path.
|
||||
*/
|
||||
GRADLE_INSTALLATION
|
||||
}
|
||||
+2
-19
@@ -23,30 +23,13 @@ import java.io.Serializable
|
||||
* Message sent from client to server to initialize the tooling API client in the given directory.
|
||||
*
|
||||
* @property directory The absolute path to the root directory of the project to initialize.
|
||||
* @property gradleInstallation The installation path of the Gradle distribution to use.
|
||||
* @property gradleDistribution The parameters for the Gradle distribution to use.
|
||||
* @property androidParams The [AndroidInitializationParams] for initializing the Android module projects.
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
data class InitializeProjectParams @JvmOverloads constructor(
|
||||
val directory: String,
|
||||
val gradleInstallation: String = "",
|
||||
val gradleDistribution: GradleDistributionParams = GradleDistributionParams.WRAPPER,
|
||||
val androidParams: AndroidInitializationParams = AndroidInitializationParams.DEFAULT
|
||||
) : Serializable
|
||||
|
||||
/**
|
||||
* Initialization params for Android project/modules.
|
||||
*
|
||||
* @property variantSelections The map of module paths to the name of the variants which should
|
||||
* be fetched/initialized.
|
||||
*/
|
||||
data class AndroidInitializationParams(val variantSelections: Map<String, String>) : Serializable {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Default initialization params. This initializes the Android modules with default values.
|
||||
*/
|
||||
@JvmStatic
|
||||
val DEFAULT = AndroidInitializationParams(emptyMap())
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,5 +24,5 @@ package com.itsaky.androidide.tooling.api.messages
|
||||
data class TaskExecutionMessage(
|
||||
val projectPath: String?,
|
||||
val tasks: List<String>,
|
||||
val gradleInstallation: String = ""
|
||||
val gradleDistribution: GradleDistributionParams = GradleDistributionParams.WRAPPER
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user