如何为 Kotlin script 自定义 .m2 缓存目录?
结论
如果脚本使用默认的 ~/.m2/repository,可以在 CI 中将该路径设为符号链接,指向 project-root/.m2/repository,再让 CI 缓存项目下的 .m2/repository/。
@file:Repository 用于声明依赖来源,不能指定下载缓存目录。Maven 的 -Dmaven.repo.local=... 是否对 Kotlin scripting 生效,取决于脚本宿主及其依赖解析器,不能直接套用。
为什么不能直接套用 Maven 配置
Kotlin scripting 可以通过 Maven Resolver(Aether)解析依赖,无须调用 mvn。Kotlin 的 MavenDependenciesResolver 实现会自行创建解析会话,并将 @file:Repository 声明的地址加入依赖来源列表。
下面的声明只会增加一个查找依赖的位置:
@file:Repository("file:///path/to/project/.m2/repository")
从其他仓库下载的依赖不会因此写入该目录。Maven 命令行支持的配置,也只有在脚本解析器明确读取时才会生效。
在 CI 中配置符号链接
以下示例适用于 Linux、macOS 等支持符号链接的环境,前提是脚本当前确实将依赖写入 ~/.m2/repository。
在项目根目录执行以下命令,先创建符号链接,再运行 Kotlin 脚本:
set -eu
project_root="$(pwd -P)"
cache_dir="$project_root/.m2/repository"
default_repo="$HOME/.m2/repository"
mkdir -p "$cache_dir" "$HOME/.m2"
if [ -e "$default_repo" ] || [ -L "$default_repo" ]; then
echo "路径已存在,请先检查并迁移:$default_repo" >&2
exit 1
fi
ln -s "$cache_dir" "$default_repo"
# 替换为实际脚本路径
kotlin scripts/task.main.kts
创建后的目录关系为:
~/.m2/repository -> project-root/.m2/repository
脚本仍通过默认路径访问仓库,文件实际保存在项目目录中。原有的 @file:Repository 和 @file:DependsOn 声明可以保留。
这里只链接 repository 子目录,方便继续使用 ~/.m2/settings.xml,也避免将该文件中可能包含的凭据纳入项目缓存。
保存和复用缓存
将 CI 缓存路径设为以下路径,相对于项目根目录:
.m2/repository/
每次任务按以下顺序执行:
- 检出项目并恢复缓存。
- 创建符号链接,让默认仓库路径指向项目缓存目录。
- 运行 Kotlin 脚本。
- 保存更新后的缓存。
如果后续步骤换用了新的容器或执行节点,需要重新创建符号链接。恢复 .m2/repository/ 只会恢复缓存文件,不会自动创建用户主目录下的链接。
运行后可用以下命令检查:
readlink "$HOME/.m2/repository"
find .m2/repository -type f -name '*.jar' | head
首次下载依赖后,应能在项目的 .m2/repository/ 中找到对应文件。
注意事项
如果 ~/.m2/repository 已经存在,需要先检查,再迁移或备份。上面的示例遇到已有路径会停止执行,避免覆盖现有目录。不要在共享 Runner 上直接执行 rm -rf ~/.m2。
这套方法适用于任务独享的 CI 用户目录。如果多个项目共用同一个用户主目录,修改符号链接会影响其他任务,应改用隔离的容器或用户目录。
如果使用自定义脚本宿主,或解析器已经配置了其他本地仓库位置,应以具体实现为准。某个宿主支持的参数,不能当作所有 Kotlin script 都支持的通用配置。
备注:内容仅供参考。
