在使用 Scala ~8 年后,我绕道而行,学习了一种你可能听说过的小语言,叫做 Go。它并非没有缺陷(发展出一个真正的类型系统,boi!(,但它在某些方面做得比Scala所希望的要好得多。
Go 以源代码形式管理依赖项,任何明智的工程师都会认为这很可怕,直到她发现将一个人的依赖项存储在源代码控制下的vendor/
目录中是一张"摆脱监禁"的卡片,适用于依赖关系解决变得过于复杂或依赖于片状的第三方资源的情况, 比如网络。
最新版本的 Go CLI 工具附带一个名为go mod vendor
的命令,该命令将当前模块的依赖项下载到项目内的vendor/
目录中,随后可以将其签入源代码管理。撇开关于以这种方式积极和先发制人地缓存依赖项的优点的讨论不谈,我想郑重声明,这个命令非常方便。
SBT因将依赖项下载到~/.ivy2
而臭名昭著,它更像是一个由所有用户的项目共享的免费缓存,而不仅仅是一个。~/.sbt
中有一个较小的缓存,SBT本身将其用作矮胖子/土豆头先生的刮擦空间。如果这两个目录不存在,它们将自动创建和填充,但这两个目录都不打算由用户显式管理。两者都是SBT和/或Ivy的内部实现细节,不应该被"除非你知道你在做什么"搞砸。
我想要的(现在我将要求的东西(是一个sbt vendor
命令,它将完成使用项目的所有依赖项填充非托管类路径的跑腿工作。如果它还可以将运行SBT本身所需的所有内容下载到同一目录中,那将是桃色的。
是否有一个SBT插件或一些神秘的咒语序列可以用来完成我所寻求的事情?
在这个问题被一群过分热心的版主永远关闭之前,我将在这里发布让我克服这个特殊驼峰的黑客。像往常一样,解决方案最终是一个 shell 脚本:
#!/bin/bash
root="$(readlink -f "$(dirname "$0")")"
sbt="$root/.sbt-launcher"
if [ ! -x "$sbt" ]; then
echo "$sbt does not exist or is not executable"
exit 1
fi
exec "$sbt"
-ivy "$root/.ivy2"
-sbt-dir "$root/.sbt"
-sbt-boot "$root/.sbt/boot"
-sbt-launch-dir "$root/.sbt/launchers"
$@
让我们快速解开这个。首先,shell 脚本是真正的 SBT 启动器的包装器,它位于同一目录中并命名为.sbt-launcher
。任何最新版本都应该有效;您也可以从http://git.io/sbt
下载一个。
我的包装器确保四个标志始终传递给真正的 SBT 启动器:
-ivy
指定常春藤缓存的自定义位置。-sbt-dir
、-sbt-boot
和-sbt-launch-dir
共同迫使SBT停止使用帐户范围的~/.sbt
目录作为SBT JAR和其他东西的倾倒场。
我将这个 shell 脚本保存为项目中的sbt
,将.sbt-launcher
从http://git.io/sbt
放在它旁边,然后开始使用包装器而不是真正的 SBT。然后,我将在项目中创建的目录.ivy2
和.sbt
签入源代码管理。
仅此而已。这不是一个优雅的解决方案,但它很好地将我的 CI/CD 过程与 Internet 工件存储库中的波动性隔离开来。