复合构建作为Gradle中buildSrc的替代方法



在自动构建系统Gradle中,buildSrc方法已成为实现自定义插件和任务以及创建通用配置(例如依赖项和版本列表)的标准。但是它有一个很大的缺点:更改时,buildSrc程序集缓存无效。



Gradle — , . , buildSrc .



Gradle



Gradle Android Android Studio. : Android- , , , Eclipse Android-. .



Gradle Groovy ( ) Stack Overflow. , build.gradle.



, - . build.gradle . , , , . , build.gradle .



// projectRoot/build.gradle

public void configureAndroid(Project project) {
  project.android {
    compileSdkVersion 9
  }
}


// projectRoot/app/build.gradle

configureAndroid(this)

android {
  // Module specific configuration
}


, . build.gradle . data, core, domain presentation, : Gradle .



// projectRoot/android.gradle

project.android {
  compileSdkVersion 9
}


// projectRoot/app/build.gradle

apply from: '../android.gradle'


IDE, . build.gradle plugins { }, .



, , , , buildSrc . buildSrc . JVM-, IDE. : ( JUnit ) , Gradle . , , Gradle?!



buildSrc



, . buildSrc . remote , . , . , Gradle , .





: compile (Java-) -> report ( ). compile JavaCompile, Java-. report — , : buildSrc build.gradle.



report , -. buildSrc- compile report , compile . build.gradle report. , - compile , . Gradle , report , , .



, compile ? buildSrc .





, . , , build.gradle. . , , Gradle-. (included) .



buildSrc , buildSrc Gradle . ( , Android Gradle plugin). Gradle .



, . , classpath. , FROM-CACHE. , .



Gradle , . , UP-TO-DATE.



buildSrc



Reaktive . :





, . , .





. buildSrc buildSrc2. buildSrc, . classpath . buildSrc, . Gradle , settings.gradle :



// projectRoot/settings.gradle.kts

pluginManagement {
    repositories {
        google()
        jcenter()
        gradlePluginPortal()
    }
}

includeBuild("buildSrc2")

// include(":module")


buildscript { repositories { } }. includeBuild Gradle buildSrc2 .





buildSrc2? .



// projectRoot/buildSrc2/build.gradle.kts

plugins {
    `kotlin-dsl`
    `java-gradle-plugin`
}

gradlePlugin {
    //   ,        
    plugins.register("class-loader-plugin") {
        id = "class-loader-plugin"
        implementationClass = "com.example.ClassLoaderPlugin"
    }
    // ,      ,       
}


java-gradle-plugin properties, . java-gradle-plugin .



buildSrc, , Gradle-.



// ClassLoaderPlugin.kt

class ClassLoaderPlugin: Plugin<Project> {
    override fun apply(target: Project) {
        // no-op
    }
}

// Deps.kt

object Deps {
    const val kotlinStdLib = "..."
}


class-loader-plugin Deps. .



// projectRoot/app/build.gradle

plugins {
    id 'class-loader-plugin'
}

dependencies {
    implementation(Deps.kotlinStdLib)
}




build.gradle setupMultiplatformLibrary.



// projectRoot/build.gradle

void setupMultiplatformLibrary(Project project) {
    project.apply plugin: 'org.jetbrains.kotlin.multiplatform'
    project.kotlin {
        sourceSets {
            commonMain {
                dependencies {
                    implementation Deps.kotlin.stdlib.common
                }
            }

            commonTest {
                dependencies {
                    implementation Deps.kotlin.test.common
                    implementation Deps.kotlin.test.annotationsCommon
                }
            }
        }
    }
}


. Kotlin Multiplatform .



Gradle- :



// projectRoot/buildSrc2/build.gradle.kts

dependencies {
    //   Kotlin Gradle plugin,        
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
}
gradlePlugin {
    //   
    plugins.register("mpp-configuration") {
        id = "mpp-configuration"
        implementationClass = "com.badoo.reaktive.configuration.MppConfigurationPlugin"
    }
}


// MppConfigurationPlugin.kt

class MppConfigurationPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        //       "kotlin"  "android"
        target.extensions.create("configuration", MppConfigurationExtension::class.java, target)
        //        ,    ,    Kotlin
        setupMultiplatformLibrary(target)
    }

    private fun setupMultiplatformLibrary(target: Project) {
        // project.apply plugin: 'org.jetbrains.kotlin.multiplatform'
        target.apply(plugin = "org.jetbrains.kotlin.multiplatform")
        // project.kotlin {
        target.extensions.configure(KotlinMultiplatformExtension::class.java) {
            sourceSets {
                maybeCreate("commonMain").dependencies { implementation(Deps.kotlin.stdlib.common) }
                maybeCreate("commonTest").dependencies {
                    implementation(Deps.kotlin.test.common)
                    implementation(Deps.kotlin.test.annotationsCommon)
                }
            }
        }
    }
}


setupAllTargetsWithDefaultSourceSets isLinuxArm32HfpEnabled. linuxArm32Hfp, . linuxArm32Hfp, . project.name, . , .



// MppConfigurationExtension.kt

open class MppConfigurationExtension @Inject constructor(
    private val project: Project
) {
    var isLinuxArm32HfpEnabled: Boolean = false
        private set

    //    ,      ARM32
    fun enableLinuxArm32Hfp() {
        if (isLinuxArm32HfpEnabled) return
        project.plugins.findPlugin(MppConfigurationPlugin::class.java)?.setupLinuxArm32HfpTarget(project)
        isLinuxArm32HfpEnabled = true
    }
}


// MppConfigurationPlugin.kt

class MppConfigurationPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        target.extensions.create("configuration", MppConfigurationExtension::class.java, target)
        ...
    }

    fun setupLinuxArm32HfpTarget(project: Project) {
        if (!Target.shouldDefineTarget(project, Target.LINUX)) return
        project.kotlin {
            linuxArm32Hfp()
            sourceSets {
                maybeCreate("linuxArm32HfpMain").dependsOn(getByName("linuxCommonMain"))
                maybeCreate("linuxArm32HfpTest").dependsOn(getByName("linuxCommonTest"))
            }
        }
    }
}


, (disableLinuxArm32Hfp() ), Kotlin ( ). mpp-configuration configuration.



// projectRoot/reaktive/build.gradle

plugins {
    id 'mpp-configuration'
}

// 
configuration {
    enableLinuxArm32Hfp()
}


.







Binary compatibility validator, . binary-compatibility.gradle build.gradle. , .



// projectRoot/binary-compatibility.gradle

if (Target.shouldDefineTarget(target, Target.ALL_LINUX_HOSTED)) {
    apply plugin: kotlinx.validation.BinaryCompatibilityValidatorPlugin

    apiValidation {
        ignoredProjects += [
                'benchmarks',
                'jmh',
                'sample-mpp-module',
                'sample-android-app',
                'sample-js-browser-app',
                'sample-linuxx64-app',
                'sample-ios-app',
                'sample-macos-app'
        ]
    }
}


.



// projectRoot/buildSrc2/build.gradle.kts

dependencies {
    //    Binary Compatibility Plugin
    implementation("org.jetbrains.kotlinx:binary-compatibility-validator:0.2.3")
}
gradlePlugin {
    //   
    plugins.register("binary-compatibility-configuration") {
        id = "binary-compatibility-configuration"
        implementationClass = "com.badoo.reaktive.compatibility.BinaryCompatibilityConfigurationPlugin"
    }
}


// BinaryCompatibilityConfigurationPlugin.kt

class BinaryCompatibilityConfigurationPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        if (Target.shouldDefineTarget(target, Target.ALL_LINUX_HOSTED)) {
            target.apply(plugin = "binary-compatibility-validator")
            target.extensions.configure(ApiValidationExtension::class) {
                ignoredProjects.addAll(
                    listOf(
                        "benchmarks",
                        "jmh",
                        "sample-mpp-module",
                        "sample-android-app",
                        "sample-js-browser-app",
                        "sample-linuxx64-app",
                        "sample-ios-app",
                        "sample-macos-app"
                    )
                )
            }
        }
    }
}


build.gradle.



// projectRoot/build.gradle

plugins {
    id 'binary-compatibility-configuration'
}




. , , , . . .



// rootProject/dependencies/build.gradle.kts

plugins {
    `kotlin-dsl`
    `java-gradle-plugin`
}

//   
group = "com.badoo.reaktive.dependencies"
version = "SNAPSHOT"

repositories {
    jcenter()
}

gradlePlugin {
    //   ,     
    plugins.register("dependencies") {
        id = "dependencies"
        implementationClass = "com.badoo.reaktive.dependencies.DependenciesPlugin"
    }
}


Deps . . settings.gradle includeBuild("dependencies"). dependencies Deps.



// projectRoot/buildSrc2/build.gradle.kts

import com.badoo.reaktive.dependencies.Deps

plugins {
    `kotlin-dsl`
    `java-gradle-plugin`
    id("dependencies")
}

dependencies {
    //        Deps
    implementation(Deps.kotlin.plugin)
    // implementation(implementation("com.badoo.reaktive.dependencies:dependencies:SNAPSHOT"))
}

//    ,   implementation("com.badoo.reaktive.dependencies:dependencies:SNAPSHOT"),    
kotlin.sourceSets.getByName("main").kotlin.srcDir("../dependencies/src/main/kotlin")


, , IDEA ( ). , Deps buildSrc2, , buildSrc2. , , . implementation("com.badoo.reaktive.dependencies:dependencies:SNAPSHOT").



dependencies .





buildSrc . , plugins { } apply plugin: 'id' . plugins , Groovy- . , . , .



, :



apply plugin: 'android-library'

android {
    compileSdkVersion 30
}

apply plugin: 'custom-plugin'


class CustomPlugin: Plugin<Project> {
    override fun apply(target: Project) {
        target.logger.warn(
            target.extentions.getByType(BaseExtension::class)
                .compileSdkVersion.toString()
        )
    }
}


compileSdkVersion. 30. plugins { }.



plugins {
    id 'android-library'
    id 'custom-plugin'
}

android {
    compileSdkVersion 30
}


null, custom-plugin android. :



  1. apply plugin: 'custom-plugin' . , -.
  2. project.afterEvaluate { }. : , afterEvaluate afterEvaluate .
  3. API, . Gradle API, .




buildSrc, Gradle. . Groovy-, plugins { }. , .




All Articles