gradle 脚本,直接 dsl 和通过自定义函数“apply from:”调用有什么区别?

gradle script, What’s difference between direct dsl and called by a custom function of “apply from:”

首先,私有maven repo中部署了一些常用脚本:

http://domain/repo/com/d/build/script/java-project/1.0/java-project-1.0.gradle

http://domain/repo/com/d/build/script/maven/1.0/maven-1.0.gradle

在目标项目中,build.gradle

subprojects {
  apply from: 'http://domain/repo/com/d/build/script/java-project/1.0/java-project-1.0.gradle'
  apply from: 'http://domain/repo/com/d/build/script/maven/1.0/maven-1.0.gradle'
}

还可以!

但是,

ext.applyScript = { script, version ->
  apply from: "http://domain/repo/com/d/build/script/${script}/${version}/${script}-${version}.gradle"
}

subprojects {
  applyScript('java-project', '1.0')
  applyScript('maven', '1.0')
}

它将失败,消息:

"Error:Cannot add task ':javadocJar' as a task with that name already exists."

任务“:javadocJar”在脚本中定义 'java-project-1.0.gradle' 我们有几个子项目。

为什么?

顺便说一句:谁能告诉我 "apply from:" 的源位置?

自己很难定位。

问题是,在 latte 的情况下,您将脚本多次应用到同一个根项目。

这怎么可能?这很有趣,也有点棘手:

  1. 您正在将 applyScript 定义为当前 Gradle 项目的扩展容器 ext 上的闭包,
  2. 通常,apply from: ... 作为 org.gradle.api.plugins.PluginAware 接口上的方法调用 apply(Map) 处理,该接口是 org.gradle.api.Project 接口的超级接口之一
    • 这意味着每次您编写 apply ... 时,您都会在当前 Gradle 项目(指定 apply ... 的项目)上调用 apply 方法
  3. 因为您将 apply ... 定义为闭包的一部分,所以标准委托适用
    • 它在语义上与 this.apply ...
    • 相同
    • this 默认指向封闭的 class/object 这是根项目(这里不能是其他任何东西)

因此,即使看起来您正在将 2 个脚本应用到所有子项目,但实际上您将这 2 个脚本应用 N 次到根项目(N 是子项目的数量)。

您需要做的是将委托更改为正确的 Project 实例。:

  1. 您可以通过向闭包添加一个额外的参数并显式调用该参数的 apply 方法来非常轻松地做到这一点:

    ext.applyScript = { project, script, version ->
        project.apply from: "..."
    }
    
    subprojects {
        applyScript(it, 'java-project', '1.0')
        applyScript(it, 'maven', '1.0')
    }
    
  2. 或者您可以显式设置委托:

    ext.applyScript = { script, version ->
        apply from: "..."
    }
    
    subprojects {
        applyScript.resolveStrategy = Closure.DELEGATE_FIRST
        applyScript.delegate = it
    
        applyScript('java-project', '1.0')
        applyScript('maven', '1.0')
    }