Как использовать пользовательское задание в качестве артефакта - PullRequest
1 голос
/ 28 февраля 2020

У меня есть простая пользовательская задача в сценарии сборки проекта (назовем это 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 знает о правильных зависимостях и работает как шарм!

1 Ответ

1 голос
/ 28 февраля 2020

При использовании задачи в качестве обозначения артефакта она должна иметь тип AbstractArchiveTask . Поэтому для других типов задач вам придется делать что-то еще.

Подход с использованием createFile.outputs.files.singleFile хорош, так как это поддерживаемый тип (как вы можете видеть из вывода ошибок). Но причина, по которой Gradle не создает зависимость от производящей задачи, заключается в том, что File не несет эту информацию. Для этого это должно быть Provider. Но быстрый способ исправить это - просто явно указать, какая задача создает артефакт:

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

В качестве альтернативы, вы также можете изменить outputFile на Provider<File> или RegularFileProperty, используя ObjectFactory в качестве переносчика. Задача производителя информации. Я никогда не использовал их как часть 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
}
...