如何用 virtualenv_install_with_resources 把一个 Python 应用打包成 Homebrew formula?
2026/9/10 23:05:18 网站建设 项目流程

如何用 virtualenv_install_with_resources 把一个 Python 应用打包成 Homebrew formula?

【免费下载链接】brew🍺 The Package Manager for Everywhere项目地址: https://gitcode.com/GitHub_Trending/br/brew

如果你要把一个提供命令行界面的 Python 应用做成 Homebrew formula,让终端用户brew install之后直接运行,而不需要知道它是用 Python 写的、更不用手动改sys.path,那么 docs/Language-Specific-Formulae.md 给出的标准做法是:在 formula 里include Language::Python::Virtualenv,在install阶段调用virtualenv_install_with_resources,并用brew update-python-resources生成依赖的 resource 块。下面的路径假设你要打包的是一个 PyPI 上的 Python 应用(普通可 import 的库一般不满足收录条件,见 Acceptable Formulae),且已安装 Homebrew。

一、准备本地编辑 formula 的环境

在写 formula 之前,先让 Homebrew 支持本地编辑 formula(命令来自 Formula Cookbook):

brew update brew tap homebrew/core

之后在 shell 环境里设置HOMEBREW_NO_INSTALL_FROM_API=1(或写在每条install/reinstall/upgrade命令前面),强制 Homebrew 使用本地的 homebrew/core 仓库而不是 API。下文所有安装、测试命令都带上这个环境变量。

二、生成 formula 骨架并改成标准应用布局

用上游发布页上的源 tarball 地址生成骨架:

brew create https://files.pythonhosted.org/packages/.../foo-1.0.tar.gz

如果 Homebrew 报Warning: Version cannot be determined from URL,需要在 formula 里显式补充version;如果猜出的名字不对,用brew create <URL> --set-name <name>覆盖。

brew create生成的文件里,以下字段是硬要求,缺失会导致 audit 不通过:

  • desc:一句话说明公式做什么;
  • homepage:SSL/TLS 优先,且不接受没有 homepage 的 formula
  • license:使用 SPDX 标识符,例如license "BSD-2-Clause"
  • url/sha256:不可变、带校验和的源;
  • depends_on "python@3.y"3.y是文档中的占位写法,表示homebrew/core当前使用的版本化 Python formula,实际要填当前 minor 版本(见文末限制)。

改完后的公式结构与 docs/Language-Specific-Formulae.md 的文档示例一致(示例中的 URL 与 SHA-256 是占位值,需要你换成自己的源地址和真实校验和):

class Foo < Formula include Language::Python::Virtualenv desc "Example Python command-line application" homepage "https://example.com/foo" url "https://files.pythonhosted.org/packages/.../foo-1.0.tar.gz" sha256 "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1" depends_on "python@3.y" resource "dependency" do url "https://files.pythonhosted.org/packages/.../dependency-1.2.3.tar.gz" sha256 "abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1" end def install virtualenv_install_with_resources end test do assert_match version.to_s, shell_output("#{bin}/foo --version") end end

virtualenv_install_with_resources的行为在 language/python.rb 中实现,它做三件事:在libexec下创建虚拟环境;把 formula 里声明的所有resource装进该环境;最后安装 formula 本体,并把虚拟环境bin中新增的命令链接进 formula 的bin。也就是说命令链接不需要你手工处理。

三、用 update-python-resources 生成 resource 块

所有没有由其他 formula 提供的 Python 模块依赖(含递归依赖)都必须声明为resource,把每个源的版本和 SHA-256 留在 formula 里——Homebrew 的 pip 辅助函数会以禁用依赖解析的方式安装,保证依赖集合可复现。用官方命令生成或更新这些块:

brew update-python-resources foo

按需调整:

  • --print-only:只打印结果,不修改 formula,适合先预览;
  • --ignore-errors:记录所有发现的 resource,对无法解析的项留下RESOURCE-ERROR注释。该选项只对第三方 tap 有效,所有官方 Homebrew tap 都要求完整解析,此选项会被忽略;
  • --install-dependencies:安装更新 resource 所缺少的依赖;
  • --version=:按指定版本查找 resource,默认使用 formula 当前版本;
  • --package-name=:指定查找用的包名,默认从 formula 的 stable URL 推断;
  • --extra-packages/--exclude-packages:逗号分隔,在查找时加入或排除额外包。

这些命令行选项对应的持久化写法是 formula 里的pypi_packagesstanza,记录应随 formula 保存的解析器配置:package_name用于 formula 名或 URL 不能识别正确 PyPI 包的情况,extra_packages用于额外的依赖根,exclude_packages用于由其他 formula 提供的包,dependencies用于解析 resource 期间必须先安装的其他 formula:

pypi_packages package_name: "upstream-name", extra_packages: "extra-package", exclude_packages: "package-from-homebrew", dependencies: "resolver-dependency"

生成完成后,按文档要求核对生成的 URL 与校验和。

四、写测试并跑 audit

test do块会被brew test foo和 BrewTestBot 执行。共享要求里写明:测试要演练安装后的真实行为,而不是只检查可执行文件存在。Language-Specific-Formulae 给出的是断言版本输出的写法(文档示例,实际命令换成你应用的入口名):

test do assert_match version.to_s, shell_output("#{bin}/foo --version") end

注意 Formula Cookbook 同时指出foo --version这类测试偏弱;如果你的应用有真实可运行的功能(如foo build-foo input.foo),优先写功能测试。Cookbook 提到过标准测试 fixture 和从test阶段用resource安装测试文件等方式,可按需参考。

然后运行新 formula 必须通过的审计:

HOMEBREW_NO_INSTALL_FROM_API=1 brew audit --new --formula foo

brew audit会把版本猜测结果等问题一并暴露;用brew info foo核对 Homebrew 从 URL 猜出的版本是否正确,不正确就补显式version

五、本地安装验证

HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug foo

失败时--debug会提示你打开交互式 shell 排查;构建阶段还可以用HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --interactive foo在解压后的沙箱里检查上游 README 和构建方式。安装成功后的验证点:

  • 应用的命令已链接进 formula 的binvirtualenv_install_with_resources自动完成),按 Cookbook 的说法$(brew --prefix)/bin在构建期间不在 PATH 里,运行时通过 Homebrew 的链接可见;
  • brew test foo通过;
  • 虚拟环境位于libexec下,不污染用户的全局语言环境——这正是共享要求中“应用依赖必须装在 formula prefix 内”的落点。

六、可选分支:调整资源顺序与额外安装步骤

virtualenv_install_with_resources支持start_with:end_with:without:关键字,只在 resource 的安装顺序或选取不同时使用。三个关键字都接受 resource 名字符串或数组,安装顺序为start_with列出的资源、其余资源、end_with列出的资源,without列出的资源被跳过。仓库内测试(virtualenv_spec.rb)验证了组合行为:without: "resource-c", start_with: "resource-d", end_with: "resource-b"时按[resource-d, resource-c, resource-b]顺序安装。传入的 resource 名必须已在 formula 中声明,否则会抛ArgumentError

如果标准布局不够、还需要额外的安装步骤(比如显式调用pip_installpip_install_and_link),文档建议直接改用virtualenv_create,它创建虚拟环境后把控制权交给你。

限制与后续维护

  • Python 依赖必须声明为版本化 formula(示例中的python@3.y),不能依赖贡献者机器上恰好有的 Python;homebrew/core切换到新的 Python minor 版本时,依赖要跟着更新。
  • 每个 resource 都带有不可变 URL 和 SHA-256,Homebrew 的 pip 辅助函数以禁用依赖解析的方式安装,所以依赖集合由 formula 本身锁定,而不是运行时解析。
  • 不要允许应用安装后在运行时自动下载其运行所需的代码(共享要求,Language-Specific-Formulae)。
  • --ignore-errors--ignore-main-package-cooldown只对第三方 tap 生效;官方 tap 要求完整解析。
  • 提交前还需满足 Acceptable Formulae 与 Package-Acceptance-Policy.md:用brew search <formula>确认未被收录、确认没有重复的 PR 在途。

更多构建系统的模板选项见brew create --help(如--python直接生成 Python 构建模板,且brew create对 PyPI 包会顺带跑一遍 resource 解析),完整 formula API 参考 Formula Cookbook。

【免费下载链接】brew🍺 The Package Manager for Everywhere项目地址: https://gitcode.com/GitHub_Trending/br/brew

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询