Cache Brew 使用 travis ci 构建
Cache Brew builds with travis ci
我有一个 Travis CI osx
构建,它具有必须从源构建的 brew
依赖项。
我知道 Travis 具有 cache
功能,但它没有任何关于如何缓存 brew
构建或输出的文档。
知道如何在 travis 中缓存 brew
包吗?
Homebrew 允许您从源代码构建:
brew install --build-from-source [package-name]
如果你想为 Travis 缓存你的自制软件,我看到的唯一方法是创建你想要的自制软件依赖项的压缩版本,类似于 this example, travis.yml
您可以将 brew 缓存目录添加到 travis 缓存中:
cache:
directories:
- $HOME/Library/Caches/Homebrew
据我所知,travis 不支持开箱即用的自制程序缓存。
以下应缓存编译器结果:
cache:
ccache: true
directories:
- $HOME/Library/Caches/Homebrew
在 OSX 上,Travis 目前似乎默认不提供 ccache => 在使用 ccache 之前,还必须完成以下工作:
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache; fi
诚然,完成的构建仍然没有被缓存。但是导致那里的每个单独计时器 运行 的构建结果至少构建过程的大部分可以算作 "cached" 之后。
要缓存实际编译的依赖项而不是缓存源压缩包或缓存目标文件,将相应包的 Cellar
和 opt
目录添加到缓存并使用适当的 before_install 检查似乎工作正常。
您还可以添加所有 /usr/local/Cellar/
和 /usr/local/opt/
,但这会添加所有已安装的自制程序包,而不仅仅是您需要的包。
来自依赖于 openssl、libevent 和检查的项目的示例:
cache:
directories:
- /usr/local/Cellar/openssl
- /usr/local/opt/openssl
- /usr/local/Cellar/libevent
- /usr/local/opt/libevent
- /usr/local/Cellar/check
- /usr/local/opt/check
before_install:
- test -d /usr/local/opt/openssl/lib || { rmdir /usr/local/opt/openssl; brew install openssl; }
- test -d /usr/local/opt/libevent/lib || { rmdir /usr/local/opt/libevent; brew install libevent; }
- test -d /usr/local/opt/check/lib || { rmdir /usr/local/opt/check; brew install check; }
rmdir
是必需的,因为如果缓存目录不存在,TravisCI 会创建它们,如果 /usr/local/opt/$package
是目录(而不是符号链接到Cellar 中的特定安装版本)。出于同样的原因,test
测试子目录,而不是主包目录。
请注意,此方法需要您自己的项目能够获取 /usr/local/opt
中安装的依赖项。
这里有 3 个独立的、松散相关的问题:
- 缓存下载的瓶子
- 缓存locally-built瓶
- 缓存 Homebrew 元数据
您不一定需要这三个部分,因此请按照您需要的部分进行操作。
缓存下载的瓶子
添加$HOME/Library/Caches/Homebrew
到Travis的缓存(实际上,这个路径应该用brew --cache
来检索,但你不能在这里调用它,你能)
cache:
directories:
- $HOME/Library/Caches/Homebrew
运行 brew cleanup
在 before_cache
阶段 -- 否则,缓存将随着新包版本的发布而无限增长
before_cache:
- brew cleanup
缓存locally-built瓶
full code太长了,这里就不一一列举了,给出算法。
这是对上一节的补充。如果在没有它的情况下使用,请在 安装时将本地瓶保存在 Homebrew 缓存之外的某个地方步骤,并在下面的启动时步骤中以适当的名称将它们添加到缓存中。
安装时:
- 使用
brew deps
递归地检查包的依赖关系
- 如果您的环境没有可用的包瓶(
brew info <pkg>
输出中没有 (bottled)
),请包含带有 --include-build
的构建依赖项
对于每个包和依赖项,
- 如果已经安装(
brew list --versions <pkg>
成功)和最新版本(brew outdated
不存在),跳过它
- 如果存在旧版本,在以下步骤中,you'll need to install the new version alongside the old one:
brew unlink
旧版本,如果不是 keg-only(brew info
输出中没有 [keg-only]
)
- 用
--force
调用所有 brew install
- 如果有一瓶可用,就
brew install
它
如果没有瓶子,
构建并安装它 with the following sequence:
brew install --build-bottle <pkg>
brew bottle --json <pkg>
brew uninstall --ignore-dependencies <pkg>
brew install <bottle>
(似乎没有任何官方方法可以获取生成的瓶子和 JSON 文件的名称。我从 brew bottle
输出中获取瓶子名称并从中推断出 JSON 文件名。)
将瓶子信息添加到包裹的公式中
brew bottle --merge --write <json file>
将 bottle 文件以 brew --cache <pkg>
给出的适当名称保存到 Travis 缓存中
- 仅在添加瓶子信息后执行此操作——否则,您将获得源包的路径。
- (Homebrew 还为
$HOME/Library/Caches/Homebrew
中下载的文件创建符号链接。您不需要这样做。)
- 保存JSON 文件供以后使用。确保将其位置添加到 Travis 缓存中。
启动时:
brew update
如果你要
- 浏览已保存的 .json 文件。对于每一个,检查本地 bottle 是否仍然合适(通过比较版本和重建编号;您可以解析
brew info --json=v1 <pkg>
和 brew info --json=v1 <bottle>
的输出以获得此数据)。
- 删除缓存的瓶子和 .json 如果没有
- 由于此时您无法使用
brew --cache
获取瓶子的路径,因此您需要单独保存它。在撰写本文时,符号链接并未保存在 Travis 的缓存中,因此我最终使用了包含路径的常规文件。
- Re-add 如果是,则将瓶子信息输入上述公式
- 他们也不太可能更改公式中的下载 URL 而不影响版本——然后瓶子的预期缓存名称将更改,因为其中的哈希是哈希下载 URL。为此,请在添加信息后检查
brew --cache <pkg>
是否仍指向您的瓶子。
在before_cache
:
- 如果您使用的是上一节中的
brew cleanup
,请在 运行 之前将缓存中的 locally-built 瓶子文件保存在某处,因为 cleanup
可能会删除那些这次不需要。在cleanup
之后,恢复那些被删除的。
缓存 Homebrew 元数据
(同样,full code 太长,所以给出算法。)
如果您 运行 brew update --verbose
(并确保 .travis.yml
或您的 Travis 项目设置中没有秘密变量 - brew
仅在以下情况下打印许多状态消息stdout
是一个 tty)——你会看到 Homebrew 自我更新操作的确切组成——因此你应该缓存什么:
- 拉取(实际上,默认情况下
rebase
ing)到几个实际上是 git
存储库的路径:
/usr/local/Homebrew
-- 自制程序本身
/usr/local/Homebrew/Library/Taps/*/*
-- 安装的水龙头
- 检查水龙头和缓存并迁移过时的位。自从特拉维斯·卡内容被添加到现有目录结构而不是替换它,第二次,可能会出现奇怪的操作和错误,这些文件是由作为更新的一部分删除的文件引起的,但在新的 VM 中又出现了。我亲眼所见的:
- 将始终尝试将
Taps/caskroom/homebrew-cask
迁移到 Taps/homebrew/homebrew-cask
,并在 Taps/homebrew/homebrew-cask/homebrew-cask
处创建一个副本。如果缓存,此副本将导致下一个 运行 上的 "error: file exists"。
- 将始终尝试将大量 non-committed 文件导入
Taps/homebrew/homebrew-versions
因此,操作将是:
将 /usr/local/Homebrew
添加到 Travis 缓存
- 添加/usr/local/Cellar和/usr/local/opt被证明是个坏主意:首先,它们太大了,导致制作和上传缓存超时;其次,这是不安全的,因为
postinstall
脚本可能会影响系统的其他任意部分,因此每次都应该从(缓存的)bottles 安装新的包版本,而不是缓存结果。无论如何安装一个瓶子只需要几秒钟。
在 brew update
: 清理 Homebrew 代码库之前
- 如果
Taps/homebrew/homebrew-cask
存在,则删除 Taps/caskroom/homebrew-cask
目录
- 找到
/usr/local/Homebrew
下的所有git
回购(find -type d -name .git
,得到dirname
的结果)和运行 git clean -fxd
在每个到摆脱特拉维斯的剩菜
- 也可以使用
brew cleanup
清除剩余的 Homebrew 缓存(如果与上一节一起使用,请参阅其他操作)——否则,您会在 brew update
在 "Migrating cache entries..." 舞台上。
在brew update
:
- 改用
brew update --merge
——它会auto-resolve任何可能与你本地提交的瓶子信息发生冲突
当re-adding本地瓶(如果与上一节结合使用):
- 不要 re-add 将信息放入公式中(如果公式中已经存在)
- 如果包版本已更改并且您的瓶子信息出现在公式中,请将其从公式中删除并
git commit
结果。没有常用的方法可以做到这一点,因此您必须使用脚本解析和编辑公式文件,并从 bottle do
table 中删除相应的行。使用 brew formula <pkg>
. 检索公式文件的路径
安装时:
如果使用 3rd-party tap,请务必检查您是否已经安装了该 tap:
brew tap | grep -qxF <tap> || brew tap <tap>
由于符号链接没有保存在 Travis 缓存中,pin 可能不会被记住。但是检查它们也没什么坏处:
brew tap --list-pinned | grep -qxF <tap> || brew tap-pin <tap>
在before_cache
:
- 删除
Taps/homebrew/homebrew-cask/homebrew-cask
如果存在
要缓存 brew update
元数据,您 only need to cache .git
文件夹 /usr/local/Homebrew
供其他人阅读的 Travis 配置:
cache:
directories:
- $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew
before_cache:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew cleanup; fi
# Credit https://discourse.brew.sh/t/best-practice-for-homebrew-on-travis-brew-update-is-5min-to-build-time/5215/9
# Cache only .git files under "/usr/local/Homebrew" so "brew update" does not take 5min every build
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then find /usr/local/Homebrew \! -regex ".+\.git.+" -delete; fi
我有一个 Travis CI osx
构建,它具有必须从源构建的 brew
依赖项。
我知道 Travis 具有 cache
功能,但它没有任何关于如何缓存 brew
构建或输出的文档。
知道如何在 travis 中缓存 brew
包吗?
Homebrew 允许您从源代码构建:
brew install --build-from-source [package-name]
如果你想为 Travis 缓存你的自制软件,我看到的唯一方法是创建你想要的自制软件依赖项的压缩版本,类似于 this example, travis.yml
您可以将 brew 缓存目录添加到 travis 缓存中:
cache:
directories:
- $HOME/Library/Caches/Homebrew
据我所知,travis 不支持开箱即用的自制程序缓存。
以下应缓存编译器结果:
cache:
ccache: true
directories:
- $HOME/Library/Caches/Homebrew
在 OSX 上,Travis 目前似乎默认不提供 ccache => 在使用 ccache 之前,还必须完成以下工作:
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache; fi
诚然,完成的构建仍然没有被缓存。但是导致那里的每个单独计时器 运行 的构建结果至少构建过程的大部分可以算作 "cached" 之后。
要缓存实际编译的依赖项而不是缓存源压缩包或缓存目标文件,将相应包的 Cellar
和 opt
目录添加到缓存并使用适当的 before_install 检查似乎工作正常。
您还可以添加所有 /usr/local/Cellar/
和 /usr/local/opt/
,但这会添加所有已安装的自制程序包,而不仅仅是您需要的包。
来自依赖于 openssl、libevent 和检查的项目的示例:
cache:
directories:
- /usr/local/Cellar/openssl
- /usr/local/opt/openssl
- /usr/local/Cellar/libevent
- /usr/local/opt/libevent
- /usr/local/Cellar/check
- /usr/local/opt/check
before_install:
- test -d /usr/local/opt/openssl/lib || { rmdir /usr/local/opt/openssl; brew install openssl; }
- test -d /usr/local/opt/libevent/lib || { rmdir /usr/local/opt/libevent; brew install libevent; }
- test -d /usr/local/opt/check/lib || { rmdir /usr/local/opt/check; brew install check; }
rmdir
是必需的,因为如果缓存目录不存在,TravisCI 会创建它们,如果 /usr/local/opt/$package
是目录(而不是符号链接到Cellar 中的特定安装版本)。出于同样的原因,test
测试子目录,而不是主包目录。
请注意,此方法需要您自己的项目能够获取 /usr/local/opt
中安装的依赖项。
这里有 3 个独立的、松散相关的问题:
- 缓存下载的瓶子
- 缓存locally-built瓶
- 缓存 Homebrew 元数据
您不一定需要这三个部分,因此请按照您需要的部分进行操作。
缓存下载的瓶子
添加
$HOME/Library/Caches/Homebrew
到Travis的缓存(实际上,这个路径应该用brew --cache
来检索,但你不能在这里调用它,你能)cache: directories: - $HOME/Library/Caches/Homebrew
运行
brew cleanup
在before_cache
阶段 -- 否则,缓存将随着新包版本的发布而无限增长before_cache: - brew cleanup
缓存locally-built瓶
full code太长了,这里就不一一列举了,给出算法。
这是对上一节的补充。如果在没有它的情况下使用,请在 安装时将本地瓶保存在 Homebrew 缓存之外的某个地方步骤,并在下面的启动时步骤中以适当的名称将它们添加到缓存中。
安装时:
- 使用
brew deps
递归地检查包的依赖关系- 如果您的环境没有可用的包瓶(
brew info <pkg>
输出中没有(bottled)
),请包含带有--include-build
的构建依赖项
- 如果您的环境没有可用的包瓶(
对于每个包和依赖项,
- 如果已经安装(
brew list --versions <pkg>
成功)和最新版本(brew outdated
不存在),跳过它 - 如果存在旧版本,在以下步骤中,you'll need to install the new version alongside the old one:
brew unlink
旧版本,如果不是 keg-only(brew info
输出中没有[keg-only]
)- 用
--force
调用所有
brew install
- 如果有一瓶可用,就
brew install
它 如果没有瓶子,
构建并安装它 with the following sequence:
brew install --build-bottle <pkg> brew bottle --json <pkg> brew uninstall --ignore-dependencies <pkg> brew install <bottle>
(似乎没有任何官方方法可以获取生成的瓶子和 JSON 文件的名称。我从
brew bottle
输出中获取瓶子名称并从中推断出 JSON 文件名。)将瓶子信息添加到包裹的公式中
brew bottle --merge --write <json file>
将 bottle 文件以
给出的适当名称保存到 Travis 缓存中brew --cache <pkg>
- 仅在添加瓶子信息后执行此操作——否则,您将获得源包的路径。
- (Homebrew 还为
$HOME/Library/Caches/Homebrew
中下载的文件创建符号链接。您不需要这样做。)
- 保存JSON 文件供以后使用。确保将其位置添加到 Travis 缓存中。
- 如果已经安装(
- 使用
启动时:
brew update
如果你要- 浏览已保存的 .json 文件。对于每一个,检查本地 bottle 是否仍然合适(通过比较版本和重建编号;您可以解析
brew info --json=v1 <pkg>
和brew info --json=v1 <bottle>
的输出以获得此数据)。- 删除缓存的瓶子和 .json 如果没有
- 由于此时您无法使用
brew --cache
获取瓶子的路径,因此您需要单独保存它。在撰写本文时,符号链接并未保存在 Travis 的缓存中,因此我最终使用了包含路径的常规文件。
- 由于此时您无法使用
- Re-add 如果是,则将瓶子信息输入上述公式
- 他们也不太可能更改公式中的下载 URL 而不影响版本——然后瓶子的预期缓存名称将更改,因为其中的哈希是哈希下载 URL。为此,请在添加信息后检查
brew --cache <pkg>
是否仍指向您的瓶子。
- 他们也不太可能更改公式中的下载 URL 而不影响版本——然后瓶子的预期缓存名称将更改,因为其中的哈希是哈希下载 URL。为此,请在添加信息后检查
- 删除缓存的瓶子和 .json 如果没有
在
before_cache
:- 如果您使用的是上一节中的
brew cleanup
,请在 运行 之前将缓存中的 locally-built 瓶子文件保存在某处,因为cleanup
可能会删除那些这次不需要。在cleanup
之后,恢复那些被删除的。
- 如果您使用的是上一节中的
缓存 Homebrew 元数据
(同样,full code 太长,所以给出算法。)
如果您 运行 brew update --verbose
(并确保 .travis.yml
或您的 Travis 项目设置中没有秘密变量 - brew
仅在以下情况下打印许多状态消息stdout
是一个 tty)——你会看到 Homebrew 自我更新操作的确切组成——因此你应该缓存什么:
- 拉取(实际上,默认情况下
rebase
ing)到几个实际上是git
存储库的路径:/usr/local/Homebrew
-- 自制程序本身/usr/local/Homebrew/Library/Taps/*/*
-- 安装的水龙头
- 检查水龙头和缓存并迁移过时的位。自从特拉维斯·卡内容被添加到现有目录结构而不是替换它,第二次,可能会出现奇怪的操作和错误,这些文件是由作为更新的一部分删除的文件引起的,但在新的 VM 中又出现了。我亲眼所见的:
- 将始终尝试将
Taps/caskroom/homebrew-cask
迁移到Taps/homebrew/homebrew-cask
,并在Taps/homebrew/homebrew-cask/homebrew-cask
处创建一个副本。如果缓存,此副本将导致下一个 运行 上的 "error: file exists"。 - 将始终尝试将大量 non-committed 文件导入
Taps/homebrew/homebrew-versions
- 将始终尝试将
因此,操作将是:
将
/usr/local/Homebrew
添加到 Travis 缓存- 添加/usr/local/Cellar和/usr/local/opt被证明是个坏主意:首先,它们太大了,导致制作和上传缓存超时;其次,这是不安全的,因为
postinstall
脚本可能会影响系统的其他任意部分,因此每次都应该从(缓存的)bottles 安装新的包版本,而不是缓存结果。无论如何安装一个瓶子只需要几秒钟。
- 添加/usr/local/Cellar和/usr/local/opt被证明是个坏主意:首先,它们太大了,导致制作和上传缓存超时;其次,这是不安全的,因为
在
brew update
: 清理 Homebrew 代码库之前- 如果
Taps/homebrew/homebrew-cask
存在,则删除Taps/caskroom/homebrew-cask
目录 - 找到
/usr/local/Homebrew
下的所有git
回购(find -type d -name .git
,得到dirname
的结果)和运行git clean -fxd
在每个到摆脱特拉维斯的剩菜 - 也可以使用
brew cleanup
清除剩余的 Homebrew 缓存(如果与上一节一起使用,请参阅其他操作)——否则,您会在brew update
在 "Migrating cache entries..." 舞台上。
- 如果
在
brew update
:- 改用
brew update --merge
——它会auto-resolve任何可能与你本地提交的瓶子信息发生冲突
- 改用
当re-adding本地瓶(如果与上一节结合使用):
- 不要 re-add 将信息放入公式中(如果公式中已经存在)
- 如果包版本已更改并且您的瓶子信息出现在公式中,请将其从公式中删除并
git commit
结果。没有常用的方法可以做到这一点,因此您必须使用脚本解析和编辑公式文件,并从bottle do
table 中删除相应的行。使用brew formula <pkg>
. 检索公式文件的路径
安装时:
如果使用 3rd-party tap,请务必检查您是否已经安装了该 tap:
brew tap | grep -qxF <tap> || brew tap <tap>
由于符号链接没有保存在 Travis 缓存中,pin 可能不会被记住。但是检查它们也没什么坏处:
brew tap --list-pinned | grep -qxF <tap> || brew tap-pin <tap>
在
before_cache
:- 删除
Taps/homebrew/homebrew-cask/homebrew-cask
如果存在
- 删除
要缓存 brew update
元数据,您 only need to cache .git
文件夹 /usr/local/Homebrew
供其他人阅读的 Travis 配置:
cache:
directories:
- $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew
before_cache:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew cleanup; fi
# Credit https://discourse.brew.sh/t/best-practice-for-homebrew-on-travis-brew-update-is-5min-to-build-time/5215/9
# Cache only .git files under "/usr/local/Homebrew" so "brew update" does not take 5min every build
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then find /usr/local/Homebrew \! -regex ".+\.git.+" -delete; fi