构建时在resources中创建一个文件

Ten*_*r04 3 jvm gradle gradle-kotlin-dsl

这是针对 JVM 应用程序的。

我正在创建一个属性文件,其中包含要在应用程序运行时使用的版本。我在基础项目中编写了这个任务build.gradle.kts

allprojects {
    //...

    tasks.register("createVersionPropertiesFile") {
        group = "build"
        doLast {
            val resourcesDir = File("$buildDir/resources/main").apply { mkdirs() }
            val resource = File(resourcesDir, "version.properties")
            resource.writeText("version=${project.version}")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我独立运行此任务,它会按我的预期创建文件。

为了在构建期间运行任务,我将其放入应用程序模块中build.gradle.kts

tasks.processResources {
    dependsOn += tasks["createVersionPropertiesFile"]
}
Run Code Online (Sandbox Code Playgroud)

然而,在构建过程中,资源目录实际上被删除而不是创建(或者如果是的话,它会在构建完成之前再次被删除)。因此,应用程序运行时找不到资源。

如何设置此任务在构建过程的适当阶段运行?

我知道另一种策略是在源代码的实际资源目录中创建资源文件,但我不想用这个自动生成的文件弄脏签入的源代码。我希望它只是构建的一部分。

aSe*_*emy 5

dirbuild/resources/是任务的输出processResources目录,因此(根据 Javadoc)任何其他文件都将被自动删除。

有一种更好的方法来连接任务,以便 Gradle 会将其识别为源文件,并使 Gradle 自动运行该文件。

为了简单起见,我将演示如何在没有配置的情况createVersionPropertiesFile下在单个.build.gradle.ktsallprojects {}

注册任务输入和输出

首先,确保在生成任务中注册输出目录以及输入这可以使用运行时 API来完成。任务有一个tempDirectory非常适合用作输出目录的默认目录,但如果您愿意,也可以使用自定义目录。

项目版本应设置为任务的输入属性,以便 Gradle 知道如果值更改需要重新运行任务。为了与Gradle的配置缓存兼容(project任务执行期间不得使用),它应该被定义为val任务配置块内部。

val createVersionPropertiesFileTask = tasks.register("createVersionPropertiesFile") {
  group = "build"

  // define a local val, to be compatible with Configuration Cache
  val projectVersion = project.version
  // Register the project version as a task input, so Gradle can cache the task
  inputs.property("projectVersion", projectVersion)

  // tell Gradle about the output directory
  outputs.dir(temporaryDir)

  doLast {
    val resource = File(temporaryDir, "version.properties")
    resource.writeText("version=${projectVersion}")
  }
}
Run Code Online (Sandbox Code Playgroud)

这些文档详细解释了为什么注册输入和输出是有益的。这里重要的是,借助 Gradle 的 Provider API,任务可以转换为 file-provider

作为文件提供者的任务

Java 项目是使用SourceSet组织的。这些都预先配置了我们所知道和喜爱的src/main/javasrc/test/resources,并且可以添加更多:

sourceSets {
  main {
    java {
      // add an additional source directory
      srcDir("$buildDir/some-extra-sources/java")
    }
    resources {
      // add an additional resource directory
      srcDir("$buildDir/some-extra-sources/resources")
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然您可以将输出目录硬编码为createVersionPropertiesFile附加资源目录,但 Gradle 不知道它需要运行任务来生成文件。我们可以进行二买一的交易:添加一个新的资源目录,告诉 Gradle 它需要运行该任务。

sourceSets {
  main {
    resources {
      // add a new resource dir that is produced by the task
      srcDir(createVersionPropertiesFileTask.map { it.temporaryDir })
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,无需添加任何dependsOn(createVersionPropertiesFileTask)- 因此您可以删除tasks.processResources.

现在,当您运行时,您将看到任务./gradlew build将生成您的自定义文件。build/resourcesprocessResources

如果您使用 IntelliJ,还有一个小好处:它将在项目资源管理器侧栏中突出显示新的资源目录。

为所有项目配置任务

您可能会发现有问题的是使用allprojects {}为所有项目配置此任务。(还有一些其他 原因 导致我们allprojects {}subprojects {}鼓励。)

相反,考虑创建一个约定插件,使用buildSrccreateVersionPropertiesFileTask通过几个简单的步骤创建和配置:

  1. 创建buildSrc/build.gradle.kts并且,由于 buildSrc 实际上是一个独立的项目,buildSrc/settings.gradle.kts

  2. 应用kotlin-dsl插件buildSrc/build.gradle.kts,这样我们就可以制作预编译脚本插件了。

  3. 使用上面提供的配置为您的约定创建一个文件。

    // ./buildSrc/src/main/kotlin/my-java-conventions.gradle.kts
    
    plugins {
      java
    }
    
    val createVersionPropertiesFileTask = tasks.register("createVersionPropertiesFile") {
      group = "build"
    
      val projectVersion = project.version
      inputs.property("projectVersion", projectVersion)
    
      outputs.dir(temporaryDir)
    
      doLast {
        val resource = File(temporaryDir, "version.properties")
        resource.writeText("version=${projectVersion}")
      }
    }
    
    sourceSets {
      main {
        resources {
          srcDir(createVersionPropertiesFileTask.map { it.temporaryDir })
        }
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 现在,在所有子项目中,您可以在需要的地方专门应用约定插件 - 不再需要allprojects {}

    // ./app-subproject/build.gradle.kts
    
    plugins {
      `my-java-conventions`
    }
    
    Run Code Online (Sandbox Code Playgroud)

写入属性任务

由于您正在生成.properties文件,因此您可能还需要考虑使用内置任务类型来生成属性 - WriteProperties。它有一些实用程序用于添加多个属性,并确保生成的文件是可重复生成的(以便 Gradle 的缓存运行良好。)

也可以看看