Gradle【有与无】【运行Gradle构建】【G9_2】优化构建时间-构建缓存
目录1.构建缓存2.总览3.启用构建缓存4.任务输出缓存4.1.它是什么样子的5.可缓存的任务5.1.内置可缓存任务5.2.第三方插件5.3.声明任务输入和输出6.启用不可缓存任务的缓存6.1.使用注释6.2.使用运行时API7.配置构建缓存7.1.内置本地构建缓存7.2.远程HTTP构建缓存7.3.配置用例7.4.构建缓存和复合...
目录
1.构建缓存
💡是否想了解顶级工程团队用来保持构建快速和高性能的提示和技巧?在此处注册以获取我们的构建缓存培训。
✨此处描述的构建缓存功能与Android插件构建缓存不同。
2.总览
Gradle 构建缓存是一种缓存机制,旨在通过重用其他构建生成的输出来节省时间。构建缓存通过以下方式工作:存储(本地或远程)构建输出,并允许构建在确定输入未更改时从缓存中获取这些输出,从而避免了重新生成它们的昂贵工作。
使用构建缓存的第一个功能是任务输出缓存。本质上,任务输出缓存利用了与Gradle用于避免以前的本地版本已经产生一组任务输出的最新检查相同的情报。但是,任务输出缓存不仅限于同一个工作空间中的先前版本,还使Gradle可以重用本地计算机上任何位置的任何早期版本的任务输出。当使用共享的构建缓存进行任务输出缓存时,这甚至可以在开发人员机器和构建代理之间使用。
除任务外,工件转换还可以利用构建缓存并类似于任务输出缓存来重用其输出。
💡有关学习如何使用构建缓存的动手方法,请尝试使用“构建缓存”指南。它涵盖了可以改进缓存的不同方案,并详细讨论了为构建启用缓存时需要注意的不同警告。
3.启用构建缓存
默认情况下,不启用构建缓存。您可以通过以下两种方式启用构建缓存:
在命令行上运行--build-cache
Gradle仅将构建缓存用于此构建。
将org.gradle.caching=true
放在你的gradle.properties中
除非使用显式禁用,否则Gradle将尝试对所有构建重用先前构建的输出--no-build-cache
。
启用构建缓存后,它将在Gradle用户主目录中存储构建输出。有关配置此目录或其他类型的构建缓存的信息,请参阅“配置构建缓存”。
4.任务输出缓存
除了最新检查中描述的增量构建之外,Gradle还可以通过将输入与任务匹配来重用任务以前执行的输出,从而节省时间。任务输出可以通过构建缓存在一台计算机上的构建之间,甚至在不同计算机上运行的构建之间重复使用。
我们关注的用例是用户拥有整个组织范围内的远程构建缓存,该缓存由连续的集成构建定期填充。开发人员和其他持续集成代理应从远程构建缓存中加载缓存条目。我们希望开发人员不会被允许填充远程构建缓存,并且所有连续集成构建都会在运行clean
任务后填充构建缓存。
为了使您的构建能够很好地使用任务输出缓存,它必须与增量构建功能一起正常工作。例如,当连续两次运行构建时,所有带有输出的任务都应为UP-TO-DATE
。在不满足此先决条件的情况下启用任务输出缓存时,您不能期望更快的构建或正确的构建。
启用构建缓存时,将自动启用任务输出缓存,请参阅启用构建缓存。
4.1.它是什么样子的
让我们从使用Java插件的项目开始,该项目具有一些Java源文件。我们是第一次运行构建。
> gradle --build-cache compileJava
:compileJava
:processResources
:classes
:jar
:assemble
BUILD SUCCESSFUL
我们在输出中看到本地构建缓存使用的目录。除此之外,构建与没有构建缓存的情况相同。让我们清理并再次运行构建。
> gradle clean
:clean
BUILD SUCCESSFUL
> gradle --build-cache assemble
:compileJava FROM-CACHE
:processResources
:classes
:jar
:assemble
BUILD SUCCESSFUL
现在我们看到,不是执行:compileJava
任务,而是从构建缓存中加载了任务的输出。由于其他任务不可缓存,因此尚未从构建缓存中加载其他任务。这是由于:classes
和:assemble
是生命周期的任务,:processResources
和:jar
是Copy-like的任务,因为它通常是更快地执行它们哪些是不可缓存的任务。
5.可缓存的任务
由于任务描述了其所有输入和输出,因此Gradle可以计算生成缓存密钥,该密钥根据其输入唯一定义任务的输出。该构建缓存键用于从构建缓存请求先前的输出或将新的输出存储在构建缓存中。如果先前的构建输出已经被其他人(例如您的持续集成服务器或其他开发人员)存储在缓存中,则可以避免在本地执行大多数任务。
下列输入以与最新检查相同的方式为任务的构建缓存键提供帮助:
-
任务类型及其类路径
-
输出属性的名称
-
如“自定义任务类型”一节中所述,注释的属性名称和值
-
DSL通过TaskInputs添加的属性的名称和值
-
Gradle发行版,buildSrc和插件的类路径
-
当构建脚本影响任务执行时的内容
任务类型需要使用@CacheableTask批注选择加入任务输出缓存。请注意,@CacheableTask不是子类继承的。自定义任务类型默认情况下不可缓存。
5.1.内置可缓存任务
当前,以下内置Gradle任务是可缓存的:
-
Java工具链: JavaCompile和 Javadoc
-
Groovy工具链: GroovyCompile, Groovydoc
-
Scala工具链: ScalaCompile, PlatformScalaCompile, ScalaDoc
-
本机工具链: CppCompile, CCompile, SwiftCompile
-
测试: Test
-
代码质量任务: Checkstyle, CodeNarc, Pmd
-
JaCoCo: JacocoMerge和 JacocoReport
-
其他任务: AntlrTask, ValidatePlugins, WriteProperties
当前所有其他内置任务都不可缓存。
5.2.第三方插件
有一些第三方插件可以很好地与构建缓存配合使用。最突出的示例是Android插件3.1+和Kotlin插件1.2.21+。对于其他第三方插件,请查看其文档以了解它们是否支持构建缓存。
5.3.声明任务输入和输出
具有可缓存任务的输入和输出的完整图片非常重要,这样一个构建的结果就可以安全地在其他地方重复使用。
缺少任务输入会导致不正确的缓存命中,其中,由于两次执行都使用相同的缓存键,因此不同的结果被视为相同。如果Gradle不能完全捕获给定任务的所有输出,则缺少任务输出会导致构建失败。错误声明的任务输入会导致高速缓存未命中,尤其是在包含易失性数据或绝对路径时。(有关应声明为输入和输出的信息,请参见“任务输入和输出”。)
✨任务路径不是构建缓存键的输入。这意味着具有不同任务路径的任务可以重用彼此的输出,只要Gradle确定执行它们会产生相同的结果即可。
为了确保正确声明了输入和输出,请使用集成测试(例如,使用TestKit)检查任务为相同的输入产生相同的输出并捕获该任务的所有输出文件。我们建议添加测试以确保任务输入可重定位,即可以将任务从缓存加载到其他构建目录中(请参阅@PathSensitive)。
为了处理任务的易失性输入,请考虑配置输入标准化。
6.启用不可缓存任务的缓存
正如我们所看到的,如果内置任务或插件提供的任务可以通过其注释进行注释,则它们是可缓存的Cacheable
。但是,如果您想使可缓存任务成为其不可缓存的类,该怎么办?让我们举一个具体的例子:您的构建脚本使用一般NpmTask
任务通过委派给NPM(并运行npm run bundle
)来创建JavaScript捆绑包。此过程类似于复杂的编译任务,但NpmTask
由于过于通用而无法默认缓存:它仅接受参数并使用这些参数运行npm。
这个任务的输入和输出很容易弄清楚。输入是包含JavaScript文件和NPM配置文件的目录。输出是此任务生成的捆绑文件。
6.1.使用注释
我们创建的子类,NpmTask
并使用批注声明输入和输出。
如果可能,最好使用委托而不是创建子类。这是内置的情况下JavaExec
,Exec
,Copy
和Sync
任务,这对一个方法Project
做实际的工作。
如果您是一名现代JavaScript开发人员,那么您就会知道捆绑可能会很长,值得缓存。为此,我们需要使用@CacheableTask批注告诉Gradle它允许缓存该任务的输出。
这足以使任务可缓存在您自己的计算机上。但是,默认情况下,输入文件由其绝对路径标识。因此,如果需要在使用不同路径的多个开发人员或计算机之间共享缓存,则将无法正常工作。因此,我们还需要设置路径灵敏度。在这种情况下,可以使用输入文件的相对路径来标识它们。
注意,可以通过覆盖基类的getter并对该方法进行注释来覆盖基类的属性注释。
例子1.定制的可缓存BundleTask
Groovy
build.gradle
@CacheableTask // (1)
class BundleTask extends NpmTask {
@Override @Internal // (2)
ListProperty<String> getArgs() {
super.getArgs()
}
@InputDirectory
@SkipWhenEmpty
@PathSensitive(PathSensitivity.RELATIVE) // (3)
final DirectoryProperty scripts = project.objects.directoryProperty()
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE) // (4)
final ConfigurableFileCollection configFiles = project.files()
@OutputFile
final RegularFileProperty bundle = project.objects.fileProperty()
BundleTask() {
args.addAll("run", "bundle")
bundle.set(project.layout.buildDirectory.file("bundle.js"))
scripts.set(project.layout.projectDirectory.dir("scripts"))
configFiles.from(project.layout.projectDirectory.file("package.json"))
configFiles.from(project.layout.projectDirectory.file("package-lock.json"))
}
}
task bundle(type: BundleTask)
-
(1)添加
@Cacheable
以启用任务缓存。 -
(2)重写基类的属性的getter,以将输入注释更改为
@Internal
。 -
(3)(4)声明路径灵敏度
6.2.使用运行时API
如果由于某种原因无法创建新的自定义任务类,则还可以使用运行时API声明输入和输出,从而使任务可缓存。
要为任务启用缓存,您需要使用TaskOutputs.cacheIf()方法。
通过运行时API进行的声明与上述注释具有相同的效果。请注意,您无法通过运行时API覆盖文件输入和输出。通过指定相同的属性名称,可以覆盖输入属性。
示例2.使包任务可缓存
Groovy
build.gradle
task bundle(type: NpmTask) {
args = ['run', 'bundle']
outputs.cacheIf { true }
inputs.dir(file("scripts"))
.withPropertyName("scripts")
.withPathSensitivity(PathSensitivity.RELATIVE)
inputs.files("package.json", "package-lock.json")
.withPropertyName("configFiles")
.withPathSensitivity(PathSensitivity.RELATIVE)
outputs.file("$buildDir/bundle.js")
.withPropertyName("bundle")
}
Kotlin
build.gradle.kts
tasks.register<NpmTask>("bundle") {
args.set(listOf("run", "bundle"))
outputs.cacheIf { true }
inputs.dir(file("scripts"))
.withPropertyName("scripts")
.withPathSensitivity(PathSensitivity.RELATIVE)
inputs.files("package.json", "package-lock.json")
.withPropertyName("configFiles")
.withPathSensitivity(PathSensitivity.RELATIVE)
outputs.file("$buildDir/bundle.js")
.withPropertyName("bundle")
}
7.配置构建缓存
您可以使用settings.gradle
中的Settings.buildCache(org.gradle.api.Action)块来配置构建缓存。
Gradle支持local
和remote
可以分别配置的构建缓存。当两个构建缓存都启用时,Gradle首先尝试从本地构建缓存加载构建输出,然后如果找不到构建输出,则尝试远程构建缓存。如果在远程缓存中找到了输出,则它们也将存储在本地缓存中,因此下次将在本地找到它们。Gradle存储(“pushes”)构建输出在已启用且BuildCache.isPush()设置为true
的任何构建缓存中。
默认情况下,本地构建缓存已启用推送,而远程构建缓存已禁用推送。
本地构建缓存已预先配置为DirectoryBuildCache并默认启用。可以通过指定要连接到的构建缓存的类型(BuildCacheConfiguration.remote(java.lang.Class))来配置远程构建缓存。
7.1.内置本地构建缓存
内置的本地构建缓存DirectoryBuildCache使用一个目录来存储构建缓存工件。默认情况下,该目录位于Gradle用户主目录中,但其位置是可配置的。
Gradle将通过删除最近尚未使用的条目来节省磁盘空间,从而定期清理本地缓存目录。
有关配置选项的更多详细信息,请参考DirectoryBuildCache的DSL文档。这是配置示例。
例子3.配置本地缓存
Groovy
settings.gradle
buildCache {
local {
directory = new File(rootDir, 'build-cache')
removeUnusedEntriesAfterDays = 30
}
}
Kotlin
settings.gradle.kts
buildCache {
local {
directory = File(rootDir, "build-cache")
removeUnusedEntriesAfterDays = 30
}
}
7.2.远程HTTP构建缓存
Gradle具有内置支持,可通过HTTP连接到远程构建缓存后端。有关协议外观的更多详细信息,请参见HttpBuildCache。请注意,通过使用以下配置,本地构建缓存将用于存储构建输出,而本地和远程构建缓存将用于检索构建输出。
例子4.从HttpBuildCache加载
Groovy
settings.gradle
buildCache {
remote(HttpBuildCache) {
url = 'https://example.com:8123/cache/'
}
}
Kotlin
settings.gradle.kts
buildCache {
remote<HttpBuildCache> {
url = uri("https://example.com:8123/cache/")
}
}
您可以配置HttpBuildCache用于访问生成缓存服务器的凭据,如以下示例所示。
例子5.配置远程HTTP缓存
Grovvy
settings.gradle
buildCache {
remote(HttpBuildCache) {
url = 'https://example.com:8123/cache/'
credentials {
username = 'build-cache-user'
password = 'some-complicated-password'
}
}
}
Kotlin
settings.gradle.kts
buildCache {
remote<HttpBuildCache> {
url = uri("https://example.com:8123/cache/")
credentials {
username = "build-cache-user"
password = "some-complicated-password"
}
}
}
✨当您尝试将生成缓存后端与HTTPS URL结合使用时,可能会遇到不受信任的SSL证书问题。理想的解决方案是为某人添加有效的SSL证书到构建缓存后端,但是我们认识到您可能无法做到这一点。在这种情况下,请将HttpBuildCache.isAllowUntrustedServer()设置为
true
。这是一个方便的解决方法,但是您不应该将其用作长期解决方案。
例子6.允许不受信任的缓存服务器
Groovy
settings.gradle
buildCache {
remote(HttpBuildCache) {
url = 'https://example.com:8123/cache/'
allowUntrustedServer = true
}
}
Kotlin
settings.gradle.kts
buildCache {
remote<HttpBuildCache> {
url = uri("https://example.com:8123/cache/")
isAllowUntrustedServer = true
}
}
7.3.配置用例
远程构建缓存的推荐用例是,持续集成服务器从干净的构建中填充它,而开发人员仅从其加载。然后,配置将如下所示。
示例7. CI推送用例的推荐设置
Groovy
settings.gradle
boolean isCiServer = System.getenv().containsKey("CI")
buildCache {
remote(HttpBuildCache) {
url = 'https://example.com:8123/cache/'
push = isCiServer
}
}
Kotlin
settings.gradle.kts
val isCiServer = System.getenv().containsKey("CI")
buildCache {
remote<HttpBuildCache> {
url = uri("https://example.com:8123/cache/")
isPush = isCiServer
}
}
如果使用buildSrc
目录,则应确保该目录使用与主版本相同的版本缓存配置。可以通过将相同的脚本应用于buildSrc/settings.gradle和
settings.gradle
如以下示例所示来实现。
示例8. buildSrc和主版本的一致设置
Groovy
settings.gradle
apply from: new File(settingsDir, 'gradle/buildCacheSettings.gradle')
gradle/buildCacheSettings.gradle
boolean isCiServer = System.getenv().containsKey("CI")
buildCache {
local {
enabled = !isCiServer
}
remote(HttpBuildCache) {
url = 'https://example.com:8123/cache/'
push = isCiServer
}
}
buildSrc/settings.gradle
apply from: new File(settingsDir, '../gradle/buildCacheSettings.gradle')
Kotlin
settings.gradle.kts
apply(from = File(settingsDir, "gradle/buildCacheSettings.gradle.kts"))
gradle/buildCacheSettings.gradle.kts
val isCiServer = System.getenv().containsKey("CI")
buildCache {
local {
isEnabled = !isCiServer
}
remote<HttpBuildCache> {
url = uri("https://example.com:8123/cache/")
isPush = isCiServer
}
}
buildSrc/settings.gradle.kts
apply(from = File(settingsDir, "../gradle/buildCacheSettings.gradle.kts"))
也可以从init脚本配置构建缓存,该脚本可以在命令行中使用,可以添加到Gradle用户主目录中,也可以作为自定义Gradle发行版的一部分
例子9.初始化脚本来配置构建缓存
Groovy
init.gradle
gradle.settingsEvaluated { settings ->
settings.buildCache {
// vvv Your custom configuration goes here
remote(HttpBuildCache) {
url = 'https://example.com:8123/cache/'
}
// ^^^ Your custom configuration goes here
}
}
Kotlin
init.gradle.kts
gradle.settingsEvaluated {
buildCache {
// vvv Your custom configuration goes here
remote<HttpBuildCache> {
url = uri("https://example.com:8123/cache/")
}
// ^^^ Your custom configuration goes here
}
}
7.4.构建缓存和复合构建
Gradle的复合构建功能允许将其他完整的Gradle构建包含到另一个构建中。无论所包含的构建是否自行定义构建缓存配置,此类包含的构建都会从顶级构建中继承构建缓存配置。
对于任何包含的构建,当前存在的构建缓存配置都将被有效忽略,而有利于顶层构建的配置。这也适用于buildSrc
任何包含的内部版本的任何项目。
8.如何设置HTTP构建缓存后端
Gradle为构建缓存节点提供Docker映像,该映像可与Gradle Enterprise连接以进行集中管理。也可以不使用功能受限的Gradle Enterprise安装缓存节点。
9.实施自己的构建缓存
使用不同的构建缓存后端存储构建输出(连接到HTTP后端的内置支持未涵盖在内)要求实现自己的逻辑以连接到自定义构建缓存后端。为此,可以通过BuildCacheConfiguration.registerBuildCacheService(java.lang.Class,java.lang.Class)注册自定义构建缓存类型。
Gradle Enterprise包含一个高性能,易于安装和操作的共享构建缓存后端。
更多推荐
所有评论(0)