代码之家  ›  专栏  ›  技术社区  ›  Hakanai

如何使类型安全访问器可用于Gradle插件提供的新项目属性?

  •  0
  • Hakanai  · 技术社区  · 4 年前

    如果我有一个定义新项目属性的插件:

    // Common plugin
    
    var copyrightDate: String? by project.extra
    

    然后尝试在生成脚本中访问此属性:

    plugins {
        `lifecycle-base`
        id("acme.common")
    }
    
    copyrightDate = "2022"
    

    我得到了可预测的结果:

    e: path\to\build.gradle.kts:7:1: Unresolved reference: copyrightDate
    

    一种变通方法 as noted in the answer here 是在每次要使用该属性时再次显式声明该属性,如:

    var copyrightDate: String? by project.extra
    

    由于我们有许多项目使用相同的插件,我宁愿让这种情况自动发生,比如应用java插件如何使 java {} 函数可用,无需声明。此机制 出现 被许多插件使用,包括Gradle本身未附带的插件。但我还没有弄清楚他们是如何做到这一点的。

    这是怎么做到的?

    • Test project 包含一个为Gradle TestKit编写的单元测试,该测试试图运行类似的构建脚本。
    1 回复  |  直到 4 年前
        1
  •  3
  •   aSemy    4 年前

    注册扩展

    官方的做法是 register an extension .

    首先创建一个扩展对象。只要它只有简单的属性,它就可以是 Gradle managed type .

    // src/main/kotlin/my/custom/plugin/MyCustomPluginSettings.kt
    package my.custom.plugin
    
    import org.gradle.api.provider.Property
    
    interface MyCustomPluginSettings {
      val copyrightDate: Property<String>
    }
    

    (我用过 Property<> 而不是 String (列出了好处 here )但你也可以用平原 一串 如果你愿意的话。)

    接下来,在您的插件中,创建扩展,并为设置默认值 copyrightDate .

    // src/main/kotlin/my/custom/plugin/MyCustomPlugin.kt
    package my.custom.plugin
    
    import org.gradle.api.*
    import org.gradle.kotlin.dsl.*
    
    abstract class MyCustomPlugin : Plugin<Project> {
      override fun apply(target: Project) {
        val myCustomPluginSettings = target.extensions.create<MyCustomPluginSettings>("myCustomPlugin")
        myCustomPluginSettings.copyrightDate.convention("2022")
      }
    }
    

    请注意,我使用的是GradleKotlin DSL。确保申请 the kotlin-dsl plugin 在您的插件中 build.gradle.kts !

    您也可以应用 MyCustomPluginSettings 以同样的方式在buildSrc插件中-只需使用 apply(...) {} 中的函数 .kts 文件

    现在,当您应用插件时,Gradle将自动生成 Kotlin DSL accessor 根据您提供的扩展名。

    // build.gradle.kts
    
    plugins {
      id("my.custom.plugin")
    }
    
    println(myCustomPlugin.copyrightDate.get())
    

    非扩展方法

    如果在中定义属性 .kt 文件,那么只要该文件包含在插件中。

    (如果您正在编写buildSrc插件,那么 .kt 文件可以在中的任何位置 ./buildSrc/src/main/kotlin/... )

    // src/main/kotlin/my/custom/plugin/constants.kt
    
    package my.custom.plugin
    
    import org.gradle.api.Project
    
    var Project.copyrightDate: String?
      get() = extra["copyrightDate"] as String?
      set(value) {
        extra["copyrightDate"] = value
      }
    

    现在在一个 build.gradle.kts 使用可以导入此。

    // build.gradle.kts
    
    import my.custom.plugin.copyrightDate
    
    plugins {
      id("my.custom.plugin")
    }
    
    println(copyrightDate)
    

    避免导入

    您可以通过以下方式避免导入: constants.kt 在源根目录中,不带包,或者在 default import packages 喜欢 org.gradle.kotlin.dsl .

    // src/main/kotlin/my/custom/plugin/constants.kt
    
    package org.gradle.kotlin.dsl
    
    import org.gradle.api.Project
    
    var Project.copyrightDate: String?
      get() = extra["copyrightDate"] as String?
      set(value) {
        extra["copyrightDate"] = value
      }
    

    由于存在冲突的风险,我只建议buildSrc插件使用此方法。但是,如果您想为更复杂的东西包括一个助手扩展,比如一个用默认版本定义依赖关系的助手函数(比如 dependencies { kotlin("reflect") } 助手功能)。