PAYATHON 2026

如何为 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/

每次任务按以下顺序执行:

  1. 检出项目并恢复缓存。
  2. 创建符号链接,让默认仓库路径指向项目缓存目录。
  3. 运行 Kotlin 脚本。
  4. 保存更新后的缓存。

如果后续步骤换用了新的容器或执行节点,需要重新创建符号链接。恢复 .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 都支持的通用配置。

备注:内容仅供参考。