摘要
brew install、brew upgrade下载很慢或中途断开时,可以自己把同一个安装包下完,放到 Homebrew 这次要读的缓存文件上,再重新执行原来的命令。下面用本机升级gh2.102.0 作例子。Homebrew7.0.8,缓存目录是~/Library/Caches/Homebrew。这次 GitHub 上的源码包下到一半就断了:curl: (18) Transferred a partial file。- 可以自己把同一个压缩包下完,再放到 Homebrew 这次要读的缓存文件上。放进去的必须是 formula 里那个 URL 的文件,SHA-256 也要一致。文件名以
brew --cache --build-from-source gh的输出为准,不能自己编哈希,也不能拷进$(brew --cellar)/gh。 gh2.102.0 在当前 API 里没有 bottle,所以这次下的就是源码包https://github.com/cli/cli/archive/refs/tags/v2.102.0.tar.gz,校验和是08bf0ef8b4409893889175e0f5279d30d6edd96465816042c0d7c72eac598158。本机缓存文件名是downloads/838ae966d01d820dbc2c41ab1f82d72064fe030ca19254fb2ff3aa993768b18d--cli-2.102.0.tar.gz。前半段是这条 URL 的 SHA-256,后半段来自下载响应里的文件名。- 校验通过后再执行原来的
brew upgrade gh或brew install gh。Homebrew 会接着做自己的校验和编译。
失败时的日志
- 下载停在源码包,formula 脚本本身已经拿到了:
text
✘ Formula gh (2.102.0) Downloading 12.8MB/-------
Error: Failed to download resource "gh (2.102.0)"
Download failed: https://github.com/cli/cli/archive/refs/tags/v2.102.0.tar.gz
curl: (18) Transferred a partial file
curl: (18)表示收到的长度和响应里声明的不一致。这次传到本地的是半截文件,不能拿去安装。浏览器、带断点续传的curl,或者换一条网络,都可以把同一个地址下完整。
缓存文件名从哪来
- 先看缓存目录,再看这个 formula 从源码构建时要用的那个文件:
bash
brew --cache
brew --cache --build-from-source gh
- 本机这两条的结果:
text
/Users/hanqf/Library/Caches/Homebrew
/Users/hanqf/Library/Caches/Homebrew/downloads/838ae966d01d820dbc2c41ab1f82d72064fe030ca19254fb2ff3aa993768b18d--cli-2.102.0.tar.gz
- 若设置过
HOMEBREW_CACHE,目录会不同,以brew --cache为准。 - 文件名分两段,中间是
--。838ae966d01d820dbc2c41ab1f82d72064fe030ca19254fb2ff3aa993768b18d是 formula URL 的 SHA-256,不是压缩包内容的校验和。cli-2.102.0.tar.gz是 GitHub 返回的文件名:仓库是cli/cli,归档名用仓库名而不是 formula 名gh。官方说明里写成<url-hash>--<formula>-<version>,见 Pre-download a file for a formula。本机实际后缀是cli-2.102.0.tar.gz。 gh2.102.0 没有 bottle,所以不加--build-from-source时,brew --cache gh打出来的也是这个源码包路径。有 bottle 的 formula 不一样:不加这个参数时路径指向 bottle,源码包必须加--build-from-source。把源码包放到 bottle 的路径上,安装时对不上。- 中断的传输会留在同一目录,文件名多一个
.incomplete。那是半截文件。完整包要放在没有这个后缀的路径上。
自己下载
- 地址就是日志里的那一条:
text
https://github.com/cli/cli/archive/refs/tags/v2.102.0.tar.gz
- 浏览器下到
~/Downloads即可。用curl时打开断点续传:
bash
mkdir -p ~/Downloads
curl -fL --retry 5 --retry-all-errors \
-C - \
-o ~/Downloads/gh-2.102.0.tar.gz \
'https://github.com/cli/cli/archive/refs/tags/v2.102.0.tar.gz'
-C -从已有文件的末尾接着下,服务器要支持 Range。本地这个文件叫gh-2.102.0.tar.gz只是为了好认,和缓存文件名不必相同。下一步mv会按缓存路径改名。
放进缓存并核对校验和
- 校验和从当前 API 里的 formula 读,版本以报错里的
2.102.0为准:
bash
brew info --json=v2 gh | python3 -c 'import json,sys; u=json.load(sys.stdin)["formulae"][0]["urls"]["stable"]; print(u["url"]); print(u["checksum"])'
- 本机输出:
text
https://github.com/cli/cli/archive/refs/tags/v2.102.0.tar.gz
08bf0ef8b4409893889175e0f5279d30d6edd96465816042c0d7c72eac598158
brew cat gh若还停在旧版本,里面的sha256对不上这次的包。安装走的是 API 里的 2.102.0。- 挪到缓存路径,再算内容的 SHA-256:
bash
CACHE_PATH="$(brew --cache --build-from-source gh)"
rm -f "${CACHE_PATH}.incomplete"
mv ~/Downloads/gh-2.102.0.tar.gz "$CACHE_PATH"
shasum -a 256 "$CACHE_PATH"
shasum的结果要和上面的08bf0ef8b4409893889175e0f5279d30d6edd96465816042c0d7c72eac598158一致。不一致就删掉$CACHE_PATH,重新下载。Homebrew 自己校验失败时也会提示删掉这个文件。
继续安装
- 还没装过:
bash
brew install gh
- 已安装、这次是升级:
bash
brew upgrade gh
- 缓存里的文件校验通过后,Homebrew 不再去下这个 tar.gz,接着解压、编译、装进 Cellar。这一步仍然要本地编译。
其他 formula
- 每次都先跑
brew --cache --build-from-source <formula>,把文件放到它打印的那一条路径上。 - 日志里的 URL 若是
ghcr.io上的 bottle,放进去的应是那个 bottle,路径用brew --cache --force-bottle <formula>。源码包不能顶替 bottle。 brew --cache只打印 formula 自己的那一个文件。formula 里若还有resource,每个资源有自己的 URL、缓存路径和 SHA-256,要分别放下。gh2.102.0 的resource是空的,这次只需要日志里的那一个 tar.gz。- 想先看 Homebrew 准备下的地址,可以执行
brew fetch --build-from-source gh。它下成功时会打出 SHA-256。下不完时,仍用上一节的brew info --json=v2读校验和,自己下完再放进缓存。