Homebrew 篇二:制作 Formula 安装脚本存入 Tap 仓库

Published: 2024-04-15

Tags: Software

本文总阅读量

前些天学习 HomeBrew 的常用命令(Homebrew 常用命令使用指北) ,了解到 Formula 是用 Ruby 编写的脚本,将脚本放到 Github 仓库,就实现了一个自定义 Tap 存储库,本篇将以我的测试 Demo easycmd 为例,制作一个 Formula 脚本,之后可以使用 brew 命令安装 easycmd

备注:Easycmd 是使用 Golang 编写的 Demo 类的工具,除用于测试、演示外,目前并没有其它功能。

编写脚本

脚本参考自 brew - yq 的 Formula 脚本 yq.rb

class Easycmd < Formula
  desc "A terminal tool sample "
  homepage "https://github.com/sincerefly/easycmd/"
  url "https://github.com/sincerefly/easycmd/archive/refs/tags/v0.0.4.tar.gz"
  sha256 "79d9b7b9fc28c1cb47ecc5c14da2e911b7da96481f043e87ec1376ca82f7f363"
  license "MIT"
  head "https://github.com/sincerefly/easycmd.git", branch: "master"

  bottle do
    root_url "https://dd-public-bucket.s3.bitiful.net/homebrew-bottles/easycmd/v0.0.4"
    #sha256 cellar: :any_skip_relocation, arm64_sonoma:   "bc36b4b41929e9e689befbecb557dbf7acf6c743ca17809f65a109ef23833c0b"
    sha256 cellar: :any_skip_relocation, arm64_ventura:  "1ec122e6913fd32af03092a2e7b3897cc77090003373f165072ab019daa2d68c"
    #sha256 cellar: :any_skip_relocation, arm64_monterey: "1d652cf11ad65dac1d8c772168f62ca6e672ee61f69f9c47b5a46819089f1cfe"
    #sha256 cellar: :any_skip_relocation, sonoma:         "3f23e27ff4f8ea8a39b07ae5b7d808d5a5cbc548124b56154c0b08585737eb23"
    #sha256 cellar: :any_skip_relocation, ventura:        "ccbd38a9b07256344d78bd127fb66f4d2b0f4831385d7458f5e36bed8f796548"
    #sha256 cellar: :any_skip_relocation, monterey:       "85a5394913a5734cef1fc388eee37e4dfb21c69e4414c8c658b8e04cb9963262"
    #sha256 cellar: :any_skip_relocation, x86_64_linux:   "8642969ca0738f0a4e632ee2877edf601e2747220460b29e8ab3368ff3e80a0e"
  end

  depends_on "go" => :build

  def install
    system "make", "build"

    bin.install "easycmd"
  end

  def post_install

    # Make sure runtime directories exist
    (var/"lib/easycmd").mkpath
    (var/"log/easycmd").mkpath
  end

  def caveats
    s = <<~EOS
      Data:    #{var}/lib/easycmd/
      Logs:    #{var}/log/easycmd/easycmd.log
      Config:  #{etc}/easycmd/
    EOS

    s
  end

  test do
    output = shell_output("#{bin}/easycmd --version").chomp
    assert output.start_with?("easycmd ")
    system "false"
  end

end

将脚本的各字段修改为正确的值,例如:

  • url 填写 github 仓库的代码下载路径,此处是 v0.0.4 的标签的源码,用于本地编译
  • sha256 是 tar.gz 源码的哈希值,macOS 可以通过 shasum -a 256 v0.0.4.tar.gz 计算得到
  • bottle 是预编译的二进制文件,匹配到就会跳过源码编译,此处我只构建了 arm64_ventura 架构/系统的二进制文件,并计算得到其 sha256 哈希值填入,这里的 root_url 是我的自定义文件下载地址,文件名为 “easycmd-0.0.4.arm64_ventura.bottle.tar.gz”,稍后会进一步介绍 Bottle 压缩包
  • depends_on 表示源码编译依赖 go 编译器
  • def install 会在未匹配到 bottle 的时候执行
  • bin.install "easycmd" 编译后生成的文件为 easycmd,bin.install 将其安装到 Brew 的 Celler 目录
  • post_install 预创建一些文件夹,程序中可以使用,无论使用 bottle 还是编译安装,post_install 都会执行
  • caveats 是在 Console 控制台输出的提示性信息
  • test 用于执行命令,测试是否安装成功

以上是一个完整的示例(非最小化示例),进一步修改代码可以参考 Github 上不同工具的 Formula Ruby 脚本

Bottle 压缩包制作

首先,构造一个目录结构,在 easycmd 文件夹下是工具版本:

easycmd 是 arm64_ventura 架构平台下二进制程序,etc 下的 bash_completion.d 是 Bash 参数自动补全脚本,我是参考 yq 的脚本进行修改的(如果你使用 brew 安装了 yq 命令,那么这个补全脚本可以在 /opt/homebrew/Cellar/yq/4.43.1/etc 找到,注意替换路径中的版本)

bash_completion.d 是可选的,此处暂不介绍。

# 创建 Bottle 包
$ tar -czvf easycmd-0.0.4.arm64_ventura.bottle.tar.gz easycmd

# 计算 Bottle 包哈希值(用于填写在 rb 脚本的 Bottle 配置段)
$ shasum -a 256 ./easycmd-0.0.4.arm64_ventura.bottle.tar.gz

文件名为什么是 easycmd-0.0.4.arm64_ventura.bottle.tar.gz 而不是其它?

是因为我是在其安装时发现它使用的是 root_url + filename, 我没找到修改的命令,姑且认为这里的文件名不能手动指定,是 Brew 的约定俗成。

我把制作好的 Bottle 包上传到 Public 存储

最终路径是

https://dd-public-bucket.s3.bitiful.net/homebrew-bottles/easycmd/v0.0.4/easycmd-0.0.4.arm64_ventura.bottle.tar.gz

上传 Formula 脚本

在上文编写的 ruby 脚本,将其 Bottle 的 Sha256 修改为刚刚计算得到的哈希值

创建 Github 仓库,例如我的测试仓库,名为 homebrew-easycmd

仓库中需要有一个 “Formula” 子文件夹,如果是 Cask 类型,则名为 “Cask”

将 easycmd.rb 文件上传

自定义的 Brew Tap 仓库即创建完成。

测试验证

添加仓库源

$ brew tap sincerefly/homebrew-easycmd

查看工具信息

$ brew info easycmd

安装工具

$ brew install easycmd

执行命令,正确输出

$ easycmd
2024/04/12 21:58:48 No config file used
hi,dong

根据上篇学习到的目录知识,对路径进行核对

/opt/homebrew/Cellar/easycmd

查看 opt 和 bin 目录下的软链接,均正确创建

如果需要测试从源码编译安装

$ brew install --build-from-source easycmd

类比扩展

Cask 和 Formula 安装包类似,以下是一个 fuse-t 的示例,可以用来模仿制作 Cask 安装方案。

https://github.com/macos-fuse-t/homebrew-cask/blob/main/Casks/fuse-t.rb

cask "fuse-t" do
  version "1.0.36"
  sha256 "8102c334ba6bb8cd9ece59fa063b30f64f9a101b45fa5ca8fe1824d3f35b6b06"

  url "https://github.com/macos-fuse-t/fuse-t/releases/download/#{version}/fuse-t-macos-installer-#{version}.pkg"
  name "fuse-t"
  desc "LibFUSE implementation that doesn't use kernel extensions"
  homepage "https://github.com/macos-fuse-t/fuse-t"

  pkg "fuse-t-macos-installer-#{version}.pkg"

  uninstall script: {
    executable: "/Library/Application Support/fuse-t/uninstall.sh",
    sudo:       true,
  }

  caveats do
    license "https://github.com/macos-fuse-t/fuse-t/blob/main/License.txt"
  end
end

遗留问题

本文创建了一个基础的 Formula 示例,但离工程化的发布/维护 Brew 存储库还有很大举例,例如:

  1. 不同架构系统的 Bottle 如何便捷、自动分发
  2. 除自定义的 OSS 存储,还有哪些托管平台更适宜存储 Bottle 文件
  3. 如何将自己开发的工具提交到 Brew 官方源,有什么标准
  4. 如何维护工具的历史版本,Brew 在安装指定版本时的机制又是怎样的

待了解的内容还可以有很多,不过眼下没有软件需要分发,Brew 软件包的封装就先探索到这里。

参考