【问题标题】:How to use custom task as artifact如何使用自定义任务作为工件
【发布时间】:2020-06-12 10:02:49
【问题描述】:

我在一个项目的(我们称之为projectA)构建脚本中有一个简单的自定义任务来创建一个文件。任务如下所示:

task createFile() {
  def outputFile = rootProject.file("${buildDir}/tmp/outputFile.txt")
  outputs.file(outputFile)
  outputs.upToDateWhen { false }
  doLast {
    outputFile.parentFile.mkdirs()
    outputFile.text = "Hello World"
  }
}

该项目是多项目构建的一部分,我需要此任务生成的文件作为 projectB 中复制任务的输入。为此,我在projectB 中创建了一个配置和一个相应的依赖项:

configurations {
  mySourceConfig
}

dependencies {
  mySourceConfig project(path: ':projectA', configuration: 'myDistConfig')
}

task copySourceDependencies(type: Copy) {
   from configurations.mySourceConfig 
   into contextDir
}

projectA 中,我有一个myDistConfig 配置,并希望使用createFile 任务的输出文件作为此配置的工件:

configurations {
  myDistConfig
}

artifacts {
  myDistConfig createFile
}

如果我这样做,gradle 会告诉我任务无法转换为ConfigurablePublishArtifact

> Cannot convert the provided notation to an object of type ConfigurablePublishArtifact: task ':projectA:createFile'.   The
  following types/formats are supported:
     - Instances of ConfigurablePublishArtifact.
     - Instances of PublishArtifact.
     - Instances of AbstractArchiveTask, for example jar.
     - Instances of Provider<RegularFile>.
     - Instances of Provider<Directory>.
     - Instances of Provider<File>.
     - Instances of RegularFile.
     - Instances of Directory.
     - Instances of File.
     - Maps with 'file' key

所以我尝试将createFile.outputs.files.singleFile 作为工件。这会阻止 gradle 抱怨,但无法设置 :projectB:copySourceDependencies:projectA:createFile 之间的依赖关系,如果在干净的工作空间上执行 projectB:copySourceDependencies,它会简单地以状态 NO-SOURCE 跳过。

是否有可能使用自定义任务作为类似于 Zip 任务的工件,以使 gradle 了解依赖关系?!


2020-02-28 更新

基于@BjørnVester 的非常好的回答,我在一个单独的 gradle 文件util.gradle 中实现了以下任务:

class CreateFile extends DefaultTask {

  @OutputFile
  RegularFileProperty outputFile = project.objects.fileProperty()

  @TaskAction
  void createFile() {
    def tOutFile = outputFile.get().asFile
    tOutFile.parentFile.mkdirs()
    tOutFile.text = "Hello World"
  }
}

rootProject.ext.CreateFile = CreateFile

在 projectA 的 build.gradle 中,如下所示:

apply from 'util.gradle'

task createFile(type: CreateFile) {
  outputFile = rootProject.file("${buildDir}/tmp/outputFile.txt")
}

artifacts {
  myDistConfig createFile.outputFile
}

现在 gradle 知道正确的依赖关系,它就像一个魅力!

【问题讨论】:

    标签: gradle gradle-dependencies gradle-task


    【解决方案1】:

    当使用任务作为工件符号时,它必须是AbstractArchiveTask 类型。因此,对于其他类型的任务,您将不得不做其他事情。

    使用createFile.outputs.files.singleFile 的方法很好,因为它是受支持的类型(从错误输出中可以看出)。但 Gradle 不创建对生产任务的依赖的原因是因为 File 不携带该信息。为此,它必须是Provider。但解决此问题的一种快速方法是明确配置生成工件的任务:

    artifacts.add("myDistConfig", createFile.outputs.files.singleFile) {
        builtBy("createFile")
    }
    

    或者,您也可以使用 ObjectFactory 将 outputFile 更改为 Provider&lt;File&gt;RegularFileProperty,因为它们携带任务生产者信息。我从未将它们用作 DSL 的一部分,它可能更适合使用类。 (虽然这看起来需要更多工作,但一旦代码增长到一定水平,它就会使代码更具可读性。)这是 Groovy 中的一个示例:

    class MyFileCreator extends DefaultTask {
      @OutputFile
      RegularFileProperty outputFile = project.objects.fileProperty().convention(project.layout.buildDirectory.file("tmp/outputFile.txt"))
    
      @TaskAction
      void createFile() {
        File outFile = outputFile.get().asFile
        outFile.parentFile.mkdirs()
        outFile.text = "Hello World"
      }
    }
    
    MyFileCreator createFileTask = tasks.create("createFile", MyFileCreator)
    
    configurations {
      myDistConfig
    }
    
    artifacts {
      myDistConfig createFileTask.outputFile
    }
    

    【讨论】:

    • 我能不能在一个 gradle 文件中定义这个任务,该文件包含在apply from: "my-file-ceator.gradle"
    • 是的,一切都应该在 Gradle 脚本文件中正常工作(甚至声明类)。另一种选择是使用buildSrc 目录,如果您想更好地组织它。
    猜你喜欢
    • 2018-07-04
    • 1970-01-01
    • 1970-01-01
    • 2017-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多