build: use Gradle Plugin and tasks to generate init script and copy tooling API to assets

This commit is contained in:
Akash Yadav
2023-11-09 01:15:05 +05:30
parent ff5b18892e
commit 611d3c3491
6 changed files with 278 additions and 72 deletions
+5 -64
View File
@@ -1,9 +1,7 @@
@file:Suppress("UnstableApiUsage")
import androidx.navigation.safe.args.generator.ext.capitalize
import com.android.build.gradle.BaseExtension
import com.itsaky.androidide.plugins.AndroidIDEAssetsPlugin
import java.util.Base64
import java.util.Locale
plugins {
id("com.android.application")
@@ -14,6 +12,10 @@ plugins {
id("androidx.navigation.safeargs.kotlin")
}
apply {
plugin(AndroidIDEAssetsPlugin::class.java)
}
android {
namespace = BuildConfig.packageName
@@ -209,64 +211,3 @@ fun getEnvOrProp(key: String): String? {
}
return value
}
tasks.create("generateInitScript") {
val out = file("src/main/assets/data/common/androidide.init.gradle")
if (out.exists()) {
out.delete()
}
doLast {
out.bufferedWriter().use {
it.write(
"""
initscript {
repositories {
// Always specify the snapshots repository first
maven {
// Add snapshots repository for AndroidIDE CI builds
url "${VersionUtils.SNAPSHOTS_REPO}"
}
mavenCentral()
google()
}
dependencies {
classpath '${BuildConfig.packageName}:gradle-plugin:$downloadVersion'
}
}
apply plugin: com.itsaky.androidide.gradle.AndroidIDEInitScriptPlugin
"""
.trimIndent()
)
}
}
}
afterEvaluate {
extensions.getByType<BaseExtension>().apply {
val flavorNames = productFlavors.map { it.name.capitalize(Locale.getDefault()) }
val dependents =
listOf(
"merge@@DebugAssets",
"merge@@ReleaseAssets",
"lintAnalyze@@Debug",
"lintAnalyze@@Release",
"lintVitalAnalyze@@Release"
)
for (dependent in dependents) {
for (flavorName in flavorNames) {
tasks.getByName(dependent.replace("@@", flavorName)).apply {
dependsOn(":subprojects:tooling-api-impl:copyJarToAssets")
dependsOn("generateInitScript")
}
}
}
}
}
+3
View File
@@ -38,6 +38,9 @@ tasks.withType<KotlinCompile> {
dependencies {
implementation(gradleApi())
implementation("com.android.tools.build:gradle:${libs.versions.agp.asProvider().get()}")
implementation(libs.common.jkotlin)
implementation(libs.common.antlr4)
implementation(libs.google.java.format)
@@ -0,0 +1,83 @@
/*
* 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.plugins
import BuildConfig
import VersionUtils
import com.android.build.api.variant.AndroidComponentsExtension
import com.itsaky.androidide.plugins.tasks.AddFileToAssetsTask
import com.itsaky.androidide.plugins.tasks.GenerateInitScriptTask
import downloadVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.configurationcache.extensions.capitalized
/**
* Handles asset copying and generation.
*
* @author Akash Yadav
*/
class AndroidIDEAssetsPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.run {
extensions.getByType(AndroidComponentsExtension::class.java).apply {
onVariants { variant ->
val variantNameCapitalized = variant.name.capitalized()
// Init script generator
val generateInitScript = tasks.register(
"generate${variantNameCapitalized}InitScript",
GenerateInitScriptTask::class.java
) {
mavenGroupId.set(BuildConfig.packageName)
snapshotsRepository.set(VersionUtils.SNAPSHOTS_REPO)
downloadVersion.set(this@run.downloadVersion)
}
variant.sources.assets?.addGeneratedSourceDirectory(
generateInitScript,
GenerateInitScriptTask::outputDir
)
// Tooling API JAR copier
val copyToolingApiJar = tasks.register(
"copy${variantNameCapitalized}ToolingApiJar",
AddFileToAssetsTask::class.java
) {
val toolingApi = rootProject.findProject(":subprojects:tooling-api-impl")!!
dependsOn(toolingApi.tasks.getByName("copyJar"))
val toolingApiJar = toolingApi.layout.buildDirectory.file(
"libs/tooling-api-all.jar")
inputFile.set(toolingApiJar)
baseAssetsPath.set("data/common")
}
variant.sources.assets?.addGeneratedSourceDirectory(
copyToolingApiJar,
AddFileToAssetsTask::outputDirectory
)
}
}
}
}
}
@@ -0,0 +1,98 @@
/*
* 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.plugins.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
/**
* Adds the provided file to assets.
*
* @author Akash Yadav
*/
abstract class AddFileToAssetsTask : DefaultTask() {
/**
* The input file that should be copied to the assets directory.
*/
@get:InputFile
abstract val inputFile: RegularFileProperty
/**
* The base assets path. The file will be saved in assets to `base-path/file-name`.
*/
@get:Input
abstract val baseAssetsPath: Property<String>
/**
* The file name of the file in assets. The file will be saved in assets to `base-path/file-name`.
*/
@get:Input
@get:Optional
abstract val fileName: Property<String>
/**
* The output assets directory. This should not be set manually, but provided to Android Gradle Plugin.
*/
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
@TaskAction
fun copy() {
var basePath = baseAssetsPath.get()
if (basePath.isBlank()) {
basePath = "data"
}
while (basePath.endsWith('/')) {
basePath = basePath.removeSuffix("/")
}
val inFile = inputFile.get().asFile
if (!inFile.exists()) {
throw IllegalArgumentException("File '$inFile' does not exist")
}
if (!inFile.isFile) {
throw IllegalArgumentException("File '$inFile' is not a file")
}
var fileName = fileName.getOrElse("")
if (fileName.isBlank()) {
fileName = inFile.name
}
val outFile = outputDirectory.file("$basePath/$fileName").get().asFile.also {
it.parentFile.mkdirs()
}
inFile.inputStream().buffered().use { input ->
outFile.outputStream().buffered().use { output ->
input.transferTo(output)
}
}
}
}
@@ -0,0 +1,81 @@
/*
* 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.plugins.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
/**
* Generates the Gradle init script for AndroidIDE.
*/
abstract class GenerateInitScriptTask : DefaultTask() {
@get:Input
abstract val downloadVersion: Property<String>
@get:Input
abstract val snapshotsRepository: Property<String>
@get:Input
abstract val mavenGroupId: Property<String>
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@TaskAction
fun generate() {
val outFile = this.outputDir.file("data/common/androidide.init.gradle")
.also {
it.get().asFile.parentFile.mkdirs()
}
outFile.get().asFile.bufferedWriter().use {
it.write(
"""
initscript {
repositories {
// Always specify the snapshots repository first
maven {
// Add snapshots repository for AndroidIDE CI builds
url "${snapshotsRepository.get()}"
}
mavenCentral()
google()
}
dependencies {
classpath '${mavenGroupId.get()}:gradle-plugin:${downloadVersion.get()}'
}
}
apply plugin: com.itsaky.androidide.gradle.AndroidIDEInitScriptPlugin
"""
.trimIndent()
)
}
}
}
@@ -26,17 +26,15 @@ tasks.withType<Jar> {
manifest { attributes("Main-Class" to "${BuildConfig.packageName}.tooling.impl.Main") }
}
tasks.register<Copy>("copyJarToAssets") {
from(project.file("${project.buildDir}/libs/tooling-api-all.jar"))
into(project.rootProject.file("app/src/main/assets/data/common/"))
tasks.register("deleteExistingJarFiles") {
delete {
delete(project.layout.buildDirectory.dir("libs"))
}
}
tasks.register("deleteExistingJarFiles") { delete { delete(project.buildDir.resolve("libs")) } }
tasks.register("copyJar") {
finalizedBy("copyJarToAssets")
doLast {
val libsDir = project.buildDir.resolve("libs")
val libsDir = project.layout.buildDirectory.dir("libs")
copy {
from(libsDir)
@@ -52,7 +50,9 @@ project.tasks.getByName("jar") {
finalizedBy("shadowJar")
}
project.tasks.getByName("shadowJar") { finalizedBy("copyJar") }
project.tasks.getByName("shadowJar") {
finalizedBy("copyJar")
}
dependencies {
api(projects.subprojects.toolingApi)