目的
无外网环境下使用Gradle离线编译,本文算是对Gradle Offline Build的翻译和补充。
问题
最近的一个项目中,我需要在一个非常严格的环境CI服务器上使用Gradle编译。这些限制是:
- 没有因特网
- 没有安装Gradle
- 没有Maven的本地仓库
显而易见,这些限制将导致项目无法编译,是因为:
- 没有安装Gradle
- 无法获取依赖
解决方案
可以通过下面的两步解决无法编译的问题:
- 使用Gradle编译
- 使用Gradle管理依赖
让我们一步一步的来解决这个问题。
Gradle Wrapper
简单来说,Gradle Wrapper可以让你不需要安装Gradle也可以使用的Gradle来编译的一种方式。它通过运行脚步来下载Gradle执行文件。(查看更多Gradle Wapper的内容)
但是CI 服务器没有外网,如何下载Gradle执行文件呢?对于本来就使用Gradle的项目,我们可以将gradle-wrapper.properties的distributionUrl修改为本地路径,比如,原有配置:
1 | distributionBase=GRADLE_USER_HOME |
修改后配置,其他配置保持不变。
1 | distributionUrl=gradle-6.5-all.zip |
然后把gradle-6.5-all.zip文件放到${projectDir}/gradle/wrapper目录下,你应该可以通过源码管理来添加。
这样,你可以在没有安装Gradle的情况下也可以使用Gradle编译了。如果是Mac或或者Linux,通过
1 | ./gradlew clean build |
本地依赖
接下来,我们需要通过Gradle管理依赖,并灵活的加载依赖。我们需要一种存储依赖的方式并有条件的把依赖加载进来。
修改build.gradle文件,
1 | ext.libs = "$projectDir/libs" |
通过这个配置,如果使用Gradle的offline模式,它会从项目的子目录中加载依赖。否则的话,他会从Gradle Home目录或者下载依赖。我选择offline参数,我觉得是最贴合这个目的的。当然,你也可以使用其他参数。
那如何存储依赖呢?我们可以编写一个copyToLibs任务。
1 | task deleteLibs(type: Delete) { |
把编译跑通的过程是这样的,在本地开发的时候,在推送的Git无服务器之前,需要先运行copyToLibs,将所有需要的依赖文件拷贝到本地,然后将这些依赖添加到Git中。
在CI服务上,运行./gradlew --offline clean build。你运行的方式可能是不一样的,但一定要确定使用了--offline参数,只有这样Gradle才知道是从本地,而不是从Gradle Home或者因特网下载依赖。
原文作者还很贴心的做了个Demo。
碰到问题及处理
虽然原文已经写得很清楚了,但自己编译时还是碰到了一些问题:
- 使用非离线模式时,正常编译,文件下载成功了,但使用离线模式时,提示找不到依赖
新版本中copyToLibs任务会随build任务执行,在离线模式时,文件已经被删除了,只留下很多0字节的依赖文件。
暂时的解决办法是在使用离线编译时,将
deleteLibs和copyToLibs的任务屏蔽掉,当然应该还用其他的办法,我暂时没有尝试。
- 在编译Spring Cloud项目时,提示部分依赖找不到。
了解了Gradle离线编译的大致逻辑之后,在线编译打包出来jar包之后,将jar包里面的所有依赖放到本地的目录中,之后编译通过。
- 部分代码使用了Lombok插件的@Data注解,但离线编译时提示无法找到对于的getter/setter方法。
临时出来办法,删除@Data注解,通过IDEA的getter/setter生成功能,修改对应的类,重新编译。
- 在使用本文方面前,我们尝试拷贝Maven库的方式来处理,但是Gradle会提示Caches里找不到对应的依赖包。
进一步了解Gradle的目录结构,看看是否有更好的离线编译方法。