brew install 或 upgrade 下载缓慢时,手动下载安装包
摘要
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 会接着做自己的校验和编译。缓存和 Cellar 的差别见 MacOS软件包管理器--brew。
失败时的日志
-
下载停在源码包,formula 脚本本身已经拿到了:
1 | ✘ Formula gh (2.102.0) Downloading 12.8MB/------- |
-
curl: (18)表示收到的长度和响应里声明的不一致。这次传到本地的是半截文件,不能拿去安装。浏览器、带断点续传的curl,或者换一条网络,都可以把同一个地址下完整。
缓存文件名从哪来
-
先看缓存目录,再看这个 formula 从源码构建时要用的那个文件:
1 | brew --cache |
-
本机这两条的结果:
1 | /Users/hanqf/Library/Caches/Homebrew |
-
若设置过
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。那是半截文件。完整包要放在没有这个后缀的路径上。
自己下载
-
地址就是日志里的那一条:
1 | https://github.com/cli/cli/archive/refs/tags/v2.102.0.tar.gz |
-
浏览器下到
~/Downloads即可。用curl时打开断点续传:
1 | mkdir -p ~/Downloads |
-
-C -从已有文件的末尾接着下,服务器要支持 Range。本地这个文件叫gh-2.102.0.tar.gz只是为了好认,和缓存文件名不必相同。下一步mv会按缓存路径改名。
放进缓存并核对校验和
-
校验和从当前 API 里的 formula 读,版本以报错里的
2.102.0为准:
1 | 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"])' |
-
本机输出:
1 | https://github.com/cli/cli/archive/refs/tags/v2.102.0.tar.gz |
-
brew cat gh若还停在旧版本,里面的sha256对不上这次的包。安装走的是 API 里的 2.102.0。 -
挪到缓存路径,再算内容的 SHA-256:
1 | CACHE_PATH="$(brew --cache --build-from-source gh)" |
-
shasum的结果要和上面的08bf0ef8b4409893889175e0f5279d30d6edd96465816042c0d7c72eac598158一致。不一致就删掉$CACHE_PATH,重新下载。Homebrew 自己校验失败时也会提示删掉这个文件。
继续安装
-
还没装过:
1 | brew install gh |
-
已安装、这次是升级:
1 | brew upgrade gh |
-
缓存里的文件校验通过后,Homebrew 不再去下这个 tar.gz,接着解压、编译、装进 Cellar。这一步仍然要本地编译。Intel 上不再提供 bottle 的说明见 MacOS软件包管理器--brew 文末「从 4.5 到 7.0」。
其他 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读校验和,自己下完再放进缓存。