groovy - 使用动态对象组配置 gradle 插件扩展的正确方法

标签 groovy gradle gradle-plugin

我正在尝试编写自己的 gradle 插件,它需要能够配置一组对象 - 这些对象中有多少以及它们的名称取决于用户。

用于创建具有高级可定制性的自定义 gradle 插件的 doco 非常差。它提到project.container()做这种事情的方法,但我不知道如何让它在我的用例中工作。

这是我的插件配置 DSL 的示例:

teregrin {
  terraformVersion = '0.6.6'

  root("dev"){
    accessKey = "flobble"
  }

  root("prd"){
  }
}

这是我的插件扩展对象,允许我配置它:
class TeregrinPluginExtension {
  boolean debug = false
  boolean forceUnzip = false
  String terraformVersion = null

  Set<TeregrinRoot> roots = []

  def root(String name, Closure c){
    def newRoot = new TeregrinRoot(name)
    c.setDelegate(newRoot)
    c()
    roots << newRoot
  }

}

我的插件中以标准方式连接的扩展:
 project.extensions.create("teregrin", TeregrinPluginExtension)

这工作正常,但它是一种非常丑陋的配置风格,并不是典型的 gradle DSL 的风格。

如何将我的插件配置 DSL 更改为如下所示:
teregrin {
  terraformVersion = '0.6.6'

  roots {
    dev {
      accessKey = "flobble"
    }

    prd {
    }
  }
}

最佳答案

实现此类 DSL 的 gradle 方法是使用 extensionscontainers :

apply plugin: SamplePlugin

whatever {
  whateverVersion = '0.6.6'
  conf {
    dev {}
    qa {}
    prod {
      accessKey = 'prod'
    }
  }
}

task printWhatever << {
  println whatever.whateverVersion
  whatever.conf.each { c ->
    println "$c.name -> $c.accessKey"
  }
}

class SamplePlugin implements Plugin<Project> {
  void apply(Project project) {
    project.extensions.create('whatever', SampleWhatever)
    project.whatever.extensions.conf = project.container(SampleConf)
    project.whatever.conf.all {
      accessKey = 'dev'
    }
  }
}

class SampleWhatever {
  String whateverVersion
}

class SampleConf {
  final String name
  String accessKey

  SampleConf(String name) {
    this.name = name
  }
}

而实现此类 DSL 的 groovy 方式是元编程 - 您需要实现 methodMissing在这种特殊情况下。下面是一个非常简单的示例,演示了它是如何工作的:
class SomeExtension {
  def devConf = new SomeExtensionConf()

  void methodMissing(String name, args) {

    if ('dev'.equals(name)) {
        def c = args[0]
        c.resolveStrategy = Closure.DELEGATE_FIRST
        c.delegate = devConf
        c()
    } else {
      throw new MissingMethodException("Could not find $name method")
    }
  }

  def getDev() {
    devConf
  }
}

class SomeExtensionConf {
  def accessKey
}

project.extensions.create('some', SomeExtension)

some {
  dev {
    accessKey = 'lol'
  }
}

assert 'lol'.equals(some.dev.accessKey)

当然它没有错误检查 - 所以 args需要验证每个参数的大小和类型 - 为简洁起见,省略了它。

当然,没有必要为每个配置创建一个单独的类(我的意思是 devprod 等)。创建一个保存配置的类并将它们全部存储在 Map 中其中 key 是配置名称。

您可以找到演示 here .

关于groovy - 使用动态对象组配置 gradle 插件扩展的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33717135/

相关文章:

java - 在 Spring Tool Suite 3.6.1 上安装 Groovy 1.8

grails - 如何将响应的读取器分配给从 httpbuilder 到 Controller 的变量

java - 将 Neo4j EmbeddedDriver 与 Spring Boot 和 SDN 结合使用失败,并出现应用程序启动时的依赖问题

Android:使用具有 gradle 依赖项的库项目时出现 ClassNotFoundException

gradle - 如何为每个 `repositories` block 或每个 RepositoryHandler 添加一个方法?

Android Gradle 3.0.0 - 为特定风格添加库依赖

time - Groovy 持续时间

java - 具有两个输出的重构方法

gradle - 同一多项目构建中插件与项目之间的依赖关系

Gradle Composite 构建忽略多项目的 resolutionStrategy 自定义