追踪 Homebrew 每天新增了哪些包
用 Homebrew 的人都会有一个好奇:每天到底新增了哪些包。Homebrew 官方提供了一个 formulae.brew.sh 页面,列出所有当前可用的 formula 和 cask,八千多个包按字母排开。但它只给当前快照,没有「今天新增了什么」这个视图。GitHub 上的 homebrew-core 仓库有完整的提交历史,八十多万次 commit,却没有按日期筛选新增包的界面。
我想把这个缺口补上,做成一个每天自动更新的页面,描述还要翻译成中文。
第一步是找数据源。formulae.brew.sh 的 JSON API 只返回当前所有包的元数据,没有历史快照。要做「新增」,必须对比两天之间的差异。最直觉的办法是 clone 整个 homebrew-core 仓库,用 git log --diff-filter=A --since --until 查指定日期新增的文件。但 homebrew-core 有八十多万次 commit,完整 clone 下来超过 1GB。我的服务器只有 1G 内存 1 核 CPU,clone 过程直接把机器拖崩了。
退一步想,其实不需要完整历史。只要知道某一天仓库里有哪些 .rb 文件,再对比前一天,多出来的就是新增。GitHub 的 tree API 正好做这件事。传一个 commit sha 进去,加 recursive=1 参数,一次性返回那个时间点仓库里所有文件的路径列表。上限是十万条目或 7MB,homebrew-core 的 Formula 目录有八千五百多个文件,远没到上限。
具体做法分三步。先调 GitHub commits API 取相邻两天各自最后一个 commit 的 sha。再用这两个 sha 分别拉 tree,提取 Formula/ 和 Casks/ 目录下的 .rb 文件名。两个集合做差集,多出来的就是当天新增的包名。
拿到包名之后,描述、主页、版本这些元数据从 formulae.brew.sh 的当前 API 查。新增包大概率还在当前列表里,查不到的就跳过。最后把英文描述批量发给 LLM 翻译成中文,保留专有名词和命令名的原文。用的是 DeepSeek V4 Flash,四十个描述打包一次请求,返回 JSON 映射,几秒处理完。
翻译这条要注意一个细节。prompt 里必须明确「只返回 JSON 对象,键为 name,值为中文翻译,不要任何解释」。否则模型会加一句「以下是翻译结果」之类的前缀,JSON 解析直接失败。即便加了约束,偶尔还是会遇到格式漂移。脚本里做了兜底,解析失败就回退到英文原文,不让一个翻译错误中断整个流程。
整个流程写成两个脚本。brew-daily.ts 跑当天,对比昨天和今天的 tree,输出当日的 JSON 文件。brew-daily-backfill.ts 接受一个日期参数,可以回填任意历史日期,原理相同。两个脚本都往 public/tools/brew-daily/data/ 目录写 <date>.json 和一个 index.json 索引。页面是纯静态 HTML,客户端 JavaScript 加载 JSON 渲染,日期选择器切换不同日期的数据。
定时任务用 cron。每天 06:00 UTC 跑一次当天脚本,结果直接写到服务器上的静态目录。data 目录被 gitignore 忽略,数据只在服务器本地,页面本身入 git。这样 git 历史干净,数据每天自动滚动更新。
中间踩了一个很实在的坑。我在服务器上试过用 SSH 跑 git clone,命令超时后本地终端显示「Command aborted」,我以为进程已经停了。实际上 SSH 超时只断开本地连接,远端进程还在跑。那个 git index-pack 一直在后台吃 42% CPU,把 1G1C 的服务器资源占满,博客服务被拖得反复崩溃重启。排查时看到 systemctl 日志里 fanshikun 服务每隔几分钟就 exit 一次,restart counter 跑到十七次,才意识到是后台 clone 没杀掉。
教训很直接。SSH 跑长任务必须用 timeout 包裹,或者超时后主动 ssh hkl 'pkill -f ...' 清理远端进程。光看本地终端的「aborted」会误判远端状态。1G1C 的机器根本不该跑 clone 这种重活,数据源的活应该交给 API,clone 留给本地 mac。
工具上线后,页面每天早上更新一次。回填历史日期只要在服务器跑一行 bun scripts/brew-daily-backfill.ts --date 2026-06-21,几秒出结果。六二十一号那天新增了三个包,一个是 GitHub Actions 的语言服务器,一个是 8BitDo 手柄固件更新器,一个是叫 Palmier Pro 的 AI 视频编辑器。翻译质量不错,「Language server for GitHub Actions YAML files」译成「GitHub Actions YAML 文件的语言服务器」,专有名词都保留了。
这个方案有几个已知限制。tree API 只能发现文件的新增和删除,识别不了重命名,一个包从 Formula/a/axxx.rb 改名到 Formula/b/bxxx.rb 会被算成一次删除加一次新增。也识别不了迁移,包从 cask 转 formula 会跨目录移动,同样被算成两次独立变化。还有一类情况是同一天内新增又被移除,如果恰好在那天最后一次 commit 时已经不在了,就完全查不到。这些边界情况数量很少,对这个工具的用途可以接受。
这个工具本身没什么技术难度。核心就是发现 formulae.brew.sh 没有历史视图,GitHub tree API 能补上这个缺口,再把 LLM 翻译接到流程末尾。真正花时间的是数据源选型和那个 SSH 进程的坑。工具做完,每天打开页面扫一眼,能发现一些平时不会注意到的有趣项目。
相关文章: