From 0edbeb136a03ddb37fe46070cfc7c4eccc08bc07 Mon Sep 17 00:00:00 2001 From: Pavlo Stavytskyi Date: Sun, 29 Oct 2023 00:41:03 -0700 Subject: [PATCH] added project decorator --- airin-gradle-android/build.gradle.kts | 1 + .../kotlin/io/morfly/airin/AndroidMetadata.kt | 20 ++++++++ .../morfly/airin/AndroidProjectDecorator.kt | 51 +++++++++++++++++++ .../airin/feature/JetpackComposeFeature.kt | 4 +- .../airin/module/AndroidLibraryModule.kt | 4 +- .../airin/plugin/AirinAndroidGradlePlugin.kt | 13 ++--- .../kotlin/io/morfly/airin/GradleProject.kt | 13 +++-- .../io/morfly/airin/GradleProjectDecorator.kt | 8 +++ .../morfly/airin/PackageDescriptorFactory.kt | 13 ----- .../morfly/airin/plugin/AirinGradlePlugin.kt | 23 ++++++--- gradle/libs.versions.toml | 1 + samples/simple-android/feature-A/BUILD.bazel | 2 +- samples/simple-android/feature-B/BUILD.bazel | 2 +- 13 files changed, 116 insertions(+), 39 deletions(-) create mode 100644 airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidMetadata.kt create mode 100644 airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidProjectDecorator.kt create mode 100644 airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProjectDecorator.kt delete mode 100644 airin-gradle-plugin/src/main/kotlin/io/morfly/airin/PackageDescriptorFactory.kt diff --git a/airin-gradle-android/build.gradle.kts b/airin-gradle-android/build.gradle.kts index ad8ff289..2022ddd2 100644 --- a/airin-gradle-android/build.gradle.kts +++ b/airin-gradle-android/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { implementation(libs.pendant.starlark) implementation(libs.pendant.library.bazel) compileOnly(libs.gradlePlugin.android.api) + compileOnly(libs.gradlePlugin.android) } gradlePlugin { diff --git a/airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidMetadata.kt b/airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidMetadata.kt new file mode 100644 index 00000000..4dc24296 --- /dev/null +++ b/airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidMetadata.kt @@ -0,0 +1,20 @@ +package io.morfly.airin + +import java.io.Serializable + +data class AndroidMetadata( + val applicationId: String?, + val packageName: String?, + val composeEnabled: Boolean +): Serializable { + + companion object { + const val ID = "androidMetadata" + } +} + +var GradleProject.androidMetadata: AndroidMetadata? + get() = properties[AndroidMetadata.ID] as? AndroidMetadata + set(value) { + properties[AndroidMetadata.ID] = value + } \ No newline at end of file diff --git a/airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidProjectDecorator.kt b/airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidProjectDecorator.kt new file mode 100644 index 00000000..7ed0cf37 --- /dev/null +++ b/airin-gradle-android/src/main/kotlin/io/morfly/airin/AndroidProjectDecorator.kt @@ -0,0 +1,51 @@ +package io.morfly.airin + +import com.android.build.api.dsl.ApplicationExtension +import com.android.build.api.dsl.CommonExtension +import com.android.build.gradle.BaseExtension +import groovy.xml.XmlSlurper +import groovy.xml.slurpersupport.NodeChild +import org.gradle.api.Project +import java.io.File + +private val xmlParser = XmlSlurper() + +open class AndroidProjectDecorator : GradleProjectDecorator { + + override fun GradleProject.decorate(target: Project) { + with(target.plugins) { + if (!hasPlugin("com.android.application") && !hasPlugin("com.android.library")) { + return + } + } + + androidMetadata = AndroidMetadata( + applicationId = target.applicationId, + packageName = target.namespace ?: target.manifestPackageName, + composeEnabled = target.composeEnabled + ) + } +} + +val Project.namespace: String? + get() = extensions.findByType(CommonExtension::class.java)?.namespace + +val Project.composeEnabled: Boolean + get() = extensions.findByType(CommonExtension::class.java)?.buildFeatures?.compose ?: false + +val Project.applicationId: String? + get() = extensions.findByType(ApplicationExtension::class.java)?.defaultConfig?.applicationId + +val Project.androidManifestFile: File? + get() = extensions.findByType(BaseExtension::class.java) + ?.sourceSets + ?.map { it.manifest.srcFile } + ?.firstOrNull(File::exists) + +val Project.manifestPackageName: String? + get() = androidManifestFile + ?.let(xmlParser::parse) + ?.list() + ?.filterIsInstance() + ?.firstOrNull { it.name() == "manifest" } + ?.attributes()?.get("package")?.toString() diff --git a/airin-gradle-android/src/main/kotlin/io/morfly/airin/feature/JetpackComposeFeature.kt b/airin-gradle-android/src/main/kotlin/io/morfly/airin/feature/JetpackComposeFeature.kt index 2cea9076..2aeea210 100644 --- a/airin-gradle-android/src/main/kotlin/io/morfly/airin/feature/JetpackComposeFeature.kt +++ b/airin-gradle-android/src/main/kotlin/io/morfly/airin/feature/JetpackComposeFeature.kt @@ -6,7 +6,7 @@ import io.morfly.airin.GradleProject import io.morfly.airin.module.AndroidLibraryModule import io.morfly.airin.module.RootModule import io.morfly.airin.plugin.AirinAndroidGradlePlugin -import io.morfly.airin.plugin.isComposeEnabled +import io.morfly.airin.composeEnabled import io.morfly.pendant.starlark.KtAndroidLibraryContext import io.morfly.pendant.starlark.artifact import io.morfly.pendant.starlark.kt_compiler_plugin @@ -21,7 +21,7 @@ abstract class JetpackComposeFeature : GradleFeatureComponent() { } override fun canProcess(target: Project): Boolean = - target.isComposeEnabled || target.plugins.hasPlugin(AirinAndroidGradlePlugin.ID) + target.composeEnabled || target.plugins.hasPlugin(AirinAndroidGradlePlugin.ID) override fun FeatureContext.onInvoke(packageDescriptor: GradleProject) { onContext(id = RootModule.ID_THIRD_PARTY_BUILD) { diff --git a/airin-gradle-android/src/main/kotlin/io/morfly/airin/module/AndroidLibraryModule.kt b/airin-gradle-android/src/main/kotlin/io/morfly/airin/module/AndroidLibraryModule.kt index bc9b4617..314baa12 100644 --- a/airin-gradle-android/src/main/kotlin/io/morfly/airin/module/AndroidLibraryModule.kt +++ b/airin-gradle-android/src/main/kotlin/io/morfly/airin/module/AndroidLibraryModule.kt @@ -6,7 +6,7 @@ import io.morfly.airin.GradleProject import io.morfly.airin.PackageContext import io.morfly.airin.applyDependenciesFrom import io.morfly.airin.feature.AndroidLibraryArtifactMappingFeature -import io.morfly.airin.property +import io.morfly.airin.androidMetadata import io.morfly.pendant.starlark.glob import io.morfly.pendant.starlark.kt_android_library import io.morfly.pendant.starlark.lang.context.BUILD @@ -35,7 +35,7 @@ abstract class AndroidLibraryModule : GradlePackageComponent() { name = packageDescriptor.name srcs = glob("src/main/**/*.kt") - custom_package = "io.morfly.airin.sample" + custom_package = packageDescriptor.androidMetadata?.packageName manifest = "src/main/AndroidManifest.xml" resource_files = glob("src/main/res/**") visibility = list["//visibility:public"] diff --git a/airin-gradle-android/src/main/kotlin/io/morfly/airin/plugin/AirinAndroidGradlePlugin.kt b/airin-gradle-android/src/main/kotlin/io/morfly/airin/plugin/AirinAndroidGradlePlugin.kt index ebf8bb32..0741a6e1 100644 --- a/airin-gradle-android/src/main/kotlin/io/morfly/airin/plugin/AirinAndroidGradlePlugin.kt +++ b/airin-gradle-android/src/main/kotlin/io/morfly/airin/plugin/AirinAndroidGradlePlugin.kt @@ -1,19 +1,12 @@ package io.morfly.airin.plugin -import com.android.build.api.dsl.ApplicationExtension -import org.gradle.api.Project -import com.android.build.api.dsl.CommonExtension +import io.morfly.airin.AndroidProjectDecorator class AirinAndroidGradlePlugin : AirinGradlePlugin() { + override val defaultDecoratorClass = AndroidProjectDecorator::class.java + companion object { const val ID = "io.morfly.airin.android" } } - -val Project.isComposeEnabled: Boolean - get() = extensions.findByType(CommonExtension::class.java)?.buildFeatures?.compose ?: false - -val Project.applicationId: String? - get() = extensions.findByType(ApplicationExtension::class.java)?.defaultConfig?.applicationId - diff --git a/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProject.kt b/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProject.kt index 32995890..389d8197 100644 --- a/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProject.kt +++ b/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProject.kt @@ -9,16 +9,23 @@ data class GradleProject( override val label: GradleLabel, override val dirPath: String, override val isRoot: Boolean, - override val ignored: Boolean, - override val packageComponentId: String?, - override val featureComponentIds: Set ) : PackageDescriptor, Serializable { + override val ignored: Boolean + get() = packageComponentId == null + + override var packageComponentId: String? = null + internal set + + override lateinit var featureComponentIds: Set + internal set + override lateinit var originalDependencies: Map> internal set override lateinit var dependencies: Map> internal set + override lateinit var subpackages: List internal set diff --git a/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProjectDecorator.kt b/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProjectDecorator.kt new file mode 100644 index 00000000..8015e6f6 --- /dev/null +++ b/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/GradleProjectDecorator.kt @@ -0,0 +1,8 @@ +package io.morfly.airin + +import org.gradle.api.Project + +interface GradleProjectDecorator { + + fun GradleProject.decorate(target: Project) +} diff --git a/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/PackageDescriptorFactory.kt b/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/PackageDescriptorFactory.kt deleted file mode 100644 index dcfb03cc..00000000 --- a/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/PackageDescriptorFactory.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.morfly.airin - -import org.gradle.api.Project - -interface PackageDescriptorFactory { - fun create(target: Project, component: GradlePackageComponent?): P -} - -class PackageDescriptorFactoryImpl: PackageDescriptorFactory { - override fun create(target: Project, component: GradlePackageComponent?): GradleProject { - TODO("Not yet implemented") - } -} diff --git a/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/plugin/AirinGradlePlugin.kt b/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/plugin/AirinGradlePlugin.kt index 58715fcf..4ff9a1b0 100644 --- a/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/plugin/AirinGradlePlugin.kt +++ b/airin-gradle-plugin/src/main/kotlin/io/morfly/airin/plugin/AirinGradlePlugin.kt @@ -9,6 +9,7 @@ import io.morfly.airin.GradlePackageComponent import io.morfly.airin.GradleProject import io.morfly.airin.InternalAirinApi import io.morfly.airin.MissingComponentResolution +import io.morfly.airin.GradleProjectDecorator import io.morfly.airin.dsl.AirinExtension import io.morfly.airin.dsl.AirinProperties import io.morfly.airin.label.GradleLabel @@ -24,6 +25,8 @@ import org.gradle.kotlin.dsl.register abstract class AirinGradlePlugin : Plugin { + abstract val defaultDecoratorClass: Class + override fun apply(target: Project) { require(target.rootProject.path == target.path) { "Airin must be applied to the root project but was applied to ${target.path}!" @@ -33,11 +36,13 @@ abstract class AirinGradlePlugin : Plugin { target.tasks.register(MigrateToBazelTask.NAME) { val components = prepareComponents(inputs.subcomponents) + val decorator = inputs.objects.newInstance(defaultDecoratorClass) val outputFiles = mutableListOf() val root = prepareProjects( root = target, components = components, properties = inputs, + decorator = decorator, outputFiles = outputFiles ) @@ -76,6 +81,7 @@ abstract class AirinGradlePlugin : Plugin { root: Project, components: Map, properties: AirinProperties, + decorator: GradleProjectDecorator, outputFiles: MutableList ): GradleProject { @@ -90,14 +96,17 @@ abstract class AirinGradlePlugin : Plugin { isRoot = target.rootProject.path == target.path, label = GradleLabel(path = target.path, name = target.name), dirPath = target.projectDir.path, - ignored = packageComponent == null, - packageComponentId = packageComponent?.id, + ).apply { + packageComponentId = packageComponent?.id featureComponentIds = featureComponents.map { it.id }.toSet() - ) - project.originalDependencies = - if (!project.ignored) prepareDependencies(target, properties) - else emptyMap() - project.subpackages = target.childProjects.values.map(::traverse) + originalDependencies = + if (!ignored) prepareDependencies(target, properties) + else emptyMap() + subpackages = target.childProjects.values.map(::traverse) + } + with(decorator) { + project.decorate(target) + } if (!project.ignored && packageComponent != null) { outputFiles += project diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ced9ec1a..5b6e050e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ pendant-library-bazel = { module = "io.morfly.pendant:pendant-library-bazel", ve gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } gradlePlugin-mavenPublish = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "mavenPublish" } gradlePlugin-android-api = { module = "com.android.tools.build:gradle-api", version.ref = "agp" } +gradlePlugin-android = { module = "com.android.tools.build:gradle", version.ref = "agp" } [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/samples/simple-android/feature-A/BUILD.bazel b/samples/simple-android/feature-A/BUILD.bazel index c8587579..9c680d17 100644 --- a/samples/simple-android/feature-A/BUILD.bazel +++ b/samples/simple-android/feature-A/BUILD.bazel @@ -4,7 +4,7 @@ load("@rules_jvm_external//:defs.bzl", "artifact") kt_android_library( name = "feature-A", srcs = glob(["src/main/**/*.kt"]), - custom_package = "io.morfly.airin.sample", + custom_package = "io.morfly.airin.sample.featureA", manifest = "src/main/AndroidManifest.xml", resource_files = glob(["src/main/res/**"]), visibility = ["//visibility:public"], diff --git a/samples/simple-android/feature-B/BUILD.bazel b/samples/simple-android/feature-B/BUILD.bazel index 0b6fd68a..dcf08545 100644 --- a/samples/simple-android/feature-B/BUILD.bazel +++ b/samples/simple-android/feature-B/BUILD.bazel @@ -4,7 +4,7 @@ load("@rules_jvm_external//:defs.bzl", "artifact") kt_android_library( name = "feature-B", srcs = glob(["src/main/**/*.kt"]), - custom_package = "io.morfly.airin.sample", + custom_package = "io.morfly.airin.sample.featureB", manifest = "src/main/AndroidManifest.xml", resource_files = glob(["src/main/res/**"]), visibility = ["//visibility:public"],