brew -- 创建自己的 Formula

摘要

  • brew是一个软件包管理器,同时支持MacOS和Linux,可以很方便地安装各种软件,比如gitnodepython等。

  • 本文介绍如何在macos下创建自己的 Formula

  • 本文基于 MacOS 15.7.2,brew 版本为 Homebrew 5.0.3。

  • 关于 brew 的安装及使用可以参考 MacOS软件包管理器--brew

从一个简单示例开始

  • 这里使用我自己编写的一个命令行脚本为例,脚本名称:color_echo,具体内容可以查看color_echo,这是一个用于终端打印彩色文本的命令。

创建一个Github仓库,用于存储 color_echo 命令

  • 创建一个Github仓库,用于存储 color_echo 命令文件,仓库名称: hanqunfeng/color_echo

  • 编写命令文件

1
2
3
4
5
mkdir color_echo_dir
cd color_echo_dir
# 感兴趣的自己去github上查看文件内容吧,这里就不贴出来了
# 这里将命令存储在了 bin 目录下,这个路径后面编写 Formula 文件时会用到
bin/color_echo
  • 提交代码并打Tag

1
2
3
4
5
6
7
8
9
10
11
# 在 color_echo_dir 目录下初始化仓库
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/hanqunfeng/color_echo.git
git push -u origin main
# 创建Tag
git tag v1.0.0
# 推送Tag
git push --tags
  • 获取tag的sha256值

1
2
3
4
wget https://github.com/hanqunfeng/color_echo/archive/refs/tags/v1.0.0.tar.gz
shasum -a 256 v1.0.0.tar.gz
## 输出
9450952a4b477c83ea2d7e28386d6ae38132bf68c46746aa218c03c21aa75f6d v1.0.0.tar.gz

发布 color_echo

brew create 命令已经失效,需要手工创建

创建 tap 仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
brew tap-new hanqunfeng/color_echo
## 输出
Warning: tap-new is a developer command, so Homebrew's
developer mode has been automatically turned on. # 提示开发者模式已自动打开
To turn developer mode off, run:
brew developer off # 如后续需要关闭开发者模式可以运行该命令

## 初始化仓库
Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/hanqunfeng/homebrew-color_echo/.git/
[main (root-commit) 35d602b] Create hanqunfeng/color_echo tap
3 files changed, 107 insertions(+)
create mode 100644 .github/workflows/publish.yml
create mode 100644 .github/workflows/tests.yml
create mode 100644 README.md
==> Created hanqunfeng/color_echo
/usr/local/Homebrew/Library/Taps/hanqunfeng/homebrew-color_echo

When a pull request making changes to a formula (or formulae) becomes green
(all checks passed), then you can publish the built bottles.
To do so, label your PR as `pr-pull` and the workflow will be triggered.

手写一个 Formula 文件

1
2
cd /usr/local/Homebrew/Library/Taps/hanqunfeng/homebrew-color_echo/Formula
touch color_echo.rb

写入内容(模板):模板格式后面会详细介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ColorEcho < Formula
desc "Print colorful text in terminal"
homepage "https://github.com/hanqunfeng/color_echo"
url "https://github.com/hanqunfeng/color_echo/archive/refs/tags/v1.0.0.tar.gz"
sha256 "9450952a4b477c83ea2d7e28386d6ae38132bf68c46746aa218c03c21aa75f6d"
license "MIT"

def install
bin.install "bin/color_echo"
end

test do
system "#{bin}/color_echo", "--help"
end
end

提交 Formula 文件到Github仓库

  • 创建一个Github仓库,用于存储 Formula 文件: hanqunfeng/homebrew-color_echo

  • 添加 Formula 文件到仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cd $(brew --repo hanqunfeng/color_echo)
git add .
git commit -m "Add color_echo 1.0.0"
git remote add origin https://github.com/hanqunfeng/homebrew-color_echo.git
git push -u origin main
## 输出
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 12 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (11/11), 2.11 KiB | 2.11 MiB/s, done.
Total 11 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/hanqunfeng/homebrew-color_echo.git
! [remote rejected] main -> main (refusing to allow a Personal Access Token to create or update workflow `.github/workflows/publish.yml` without `workflow` scope)
error: failed to push some refs to 'https://github.com/hanqunfeng/homebrew-color_echo.git'
  • 提示缺少权限,需要给仓库添加权限。在 Github 中添加一个 Personal Access Token,并添加权限repoworkflow,重新推送

1
2
3
4
5
6
7
8
9
10
11
12
13
# 设置远程仓库地址,注意替换为你的仓库地址,并且密钥替换为实际的密钥
git remote set-url origin https://ghp_xxxxx@github.com/hanqunfeng/homebrew-color_echo.git
git push -u origin main
## 输出
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 12 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (11/11), 2.11 KiB | 2.11 MiB/s, done.
Total 11 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/hanqunfeng/homebrew-color_echo.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.

安装 Formula

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 切换 tap,注意: 执行搜索和安装时需要先切换 tap,否则需要使用完整包名 hanqunfeng/color_echo/color_echo
brew tap hanqunfeng/color_echo

# 搜索
brew search color_echo
## 输出
==> Formulae
hanqunfeng/color_echo/color_echo color-code

# 完整包名搜索
brew search hanqunfeng/color_echo/color_echo
## 输出
==> Formulae
color_echo

# 安装
brew install color_echo
## 输出
==> Fetching downloads for: color_echo
✔︎ Formula color_echo (1.0.0) [Verifying 2.1KB/ 2.1KB]
==> Installing color_echo from hanqunfeng/color_echo
🍺 /usr/local/Cellar/color_echo/1.0.0: 4 files, 7.4KB, built in 5 seconds
==> Running `brew cleanup color_echo`...
Disable this behaviour by setting `HOMEBREW_NO_INSTALL_CLEANUP=1`.
Hide these hints with `HOMEBREW_NO_ENV_HINTS=1` (see `man brew`).

测试 Formula

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
color_echo --help
## 输出
用法: color_echo [参数] 内容

参数说明:
-c, --color <color> 设置前景色(文字颜色)
可选颜色: black red green yellow blue magenta cyan white

-b, --bg <color> 设置背景色
可选颜色: black red green yellow blue magenta cyan white

--bold 加粗字体
--underline 下划线
--italic 斜体字体(仅部分终端,Terminal 不支持,iTerm2 支持)

-n 不换行输出,兼容 echo 的 -n 参数

-h, --help 显示帮助信息

示例:
color_echo --color green "Hello World"
color_echo -c red -b yellow --bold "Error Message"
color_echo --underline "This is underlined"

formula 文件模板

  • Ruby语法,定义一个Formula的子类

1
2
3
4
# class 子类 < 父类
class ColorEcho < Formula

end
  • 添加属性

1
2
3
4
5
desc "Print colorful text in terminal"  # 描述
homepage "https://github.com/hanqunfeng/color_echo" # 项目地址
url "https://github.com/hanqunfeng/color_echo/archive/refs/tags/v1.0.0.tar.gz" # 下载地址,安装时会自动下载并解压
sha256 "9450952a4b477c83ea2d7e28386d6ae38132bf68c46746aa218c03c21aa75f6d" # sha256,校验v1.0.0.tar.gz
license "MIT" # 许可
  • 添加安装方法

1
2
3
4
5
6
7
8
9
def install  # Homebrew 会执行的安装步骤,工作目录为解压后的文件目录
# 这里只有一个步骤,如果要一次安装多个命令,可以多次添加 bin.install
bin.install "bin/color_echo" # 将 bin/color_echo 安装到 /usr/local/bin/color_echo
# 如果要指定安装后的命令名称,可以使用如下方式
# bin.install "bin/color_echo.sh" => "color_echo"

# 如果需要执行系统命令可以使用如下方式
# system "echo", "hello world"
end
  • 添加测试方法

1
2
3
4
5
6
test do  # Homebrew 在安装完你的 formula 之后,会在一个隔离环境中执行这段代码
# system 指令用于执行系统命令,逗号分隔相当于空格
system "#{bin}/color_echo", "--help" # 相当于执行 color_echo --help
# 断言测试
# assert_equal "2\n", pipe_output("#{bin}/jq .bar", '{"foo":1, "bar":2}')
end

#{bin}: 当前这个 formula 的「安装目录里的 bin 目录」,不同平台会不同

系统 / 架构 实际路径示例
Intel Mac /usr/local/Cellar/color_echo/1.0.0/bin
Apple Silicon /opt/homebrew/Cellar/color_echo/1.0.0/bin
Linuxbrew /home/linuxbrew/.linuxbrew/Cellar/.../bin
  • 如果当前安装的命令依赖其它命令,可以使用如下方式添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 放在 def install 方法之前
depends_on "jq" # 在安装你的 formula 之前,Homebrew 会先自动安装 jq,并保证在你的 install / test 阶段可以用
depends_on "jq" => :build # 只在构建时需要
depends_on "jq" => :test # 测试时需要
depends_on "jq" => [:build, :test] # 构建和测试都需要

# 环境约束
depends_on macos: :sonoma # 仅 macOS Sonoma
depends_on arch: :x86_64 # 仅 x86_64
depends_on xcode: ["9.3", :build] # 仅当 Xcode≥9.3 且用于 build


# 依赖第三方库中的命令要用完整包名
depends_on "hanqunfeng/color_echo/color_echo"

后记