1. 背景
我们有些情况下需要写一些shell脚本进行执行某些操作(mac环境),一般我们需要进入shell脚本目录在进行执行,或者可以通过alias添加一个别名等方案规避找shell脚本的麻烦。但是当有多个人比如一个团队都需要使用你这个脚本,普通方法就是把脚本给到其他人,其他人再在本地配置使用,但是这种方法多少有些麻烦。一个比较好的解决方案是基于brew创建一个Formula, 其他人可以通过brew install的方式进行安装直接使用,极大简化麻烦。
2. 如何创建及测试
2.1. 示例场景
我在使用brew安装某些应用的使用,由于依赖特别多,可能经常因为超时(brew install时很多安装包(tarball)放在git上)卡在某个不重复的操作上,我不得不盯着安装过程,失败时重新执行安装命令,很麻烦。解决方案:我基于brew封装一个可以重试的脚本叫‘brew-install-with-retry.sh', 并把这个脚本制作一个Formula.
2.2. 前置条件
- homebrew安装
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- 通过brew安装ruby
brew install ruby
2.3. 创建脚本
我的脚本是brew-install-with-retry.sh,内容如下
#!/bin/bash
# 脚本中的版本号
VERSION="1.0.0"
# 显示版本号
show_version() {
echo "brew-install-with-retry version ${VERSION}"
}
# 如果未指定任何参数,则显示帮助信息
if [ "$#" -eq 0 ]; then
echo "用法: $0 -p 包名 [-a 重试次数]"
echo " -p 包名: 要安装的包名"
echo " -a 重试次数: 可选参数,安装失败时的重试次数,默认为3"
exit 1
fi
# 处理命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--version|-V) show_version; exit 0;;
*) echo "Unknown parameter passed: $1"; exit 1;;
esac
shift
done
# 定义默认的重试次数
DEFAULT_MAX_ATTEMPTS=3
# 使用getopts处理命令行参数
while getopts "p:a:" opt; do
case $opt in
p)
PACKAGE="$OPTARG"
;;
a)
MAX_ATTEMPTS="$OPTARG"
;;
\?)
echo "无效的选项: -$OPTARG" >&2
exit 1
;;
:)
echo "选项 -$OPTARG 需要一个参数。" >&2
exit 1
;;
esac
done
# 如果没有提供重试次数,则使用默认值
if [ -z "$MAX_ATTEMPTS" ]; then
MAX_ATTEMPTS=$DEFAULT_MAX_ATTEMPTS
fi
# 当前重试次数
CURRENT_ATTEMPT=0
# 检查是否提供了包名
if [ -z "$PACKAGE" ]; then
echo "错误:必须提供要安装的包名。"
echo "用法: $0 -p 包名 [-a 重试次数]"
exit 1
fi
# 开始安装
until brew install $PACKAGE || [$CURRENT_ATTEMPT -eq $MAX_ATTEMPTS ]
do
echo "尝试安装 $PACKAGE, 当前尝试次数:$CURRENT_ATTEMPT"
((CURRENT_ATTEMPT++))
if [ $CURRENT_ATTEMPT -eq$MAX_ATTEMPTS ]; then
echo "已达到最大尝试次数 $MAX_ATTEMPTS,安装失败。"
exit 1
fi
sleep 5 # 等待5秒再重试
done
echo "$PACKAGE 安装成功!"
2.4. 创建homebrew-tap及formula
- 在github上创建一个homebrew-tap,并创建目录Formula (home brew的规范)
- 项目clone到本地
-
在Formula目录中创建formula(formula需要用ruby语言编写),命名为brew-install-with-retry.rb
class BrewInstallWithRetry < Formula desc "A script to install packages with retry logic" homepage "https://github.com/leon-fly/brew-install-with-retry" url "https://github.com/leon-fly/formula/raw/master/brew-install-with-retry/archive/brew-install-with-retry-1.0.0.tar.gz" sha256 "7c12edfef69db79006a3b853b433a76c182865e98f80fabc730b12b48fc4d347" license "MIT" def install bin.install "brew-install-with-retry.sh" => "brew-install-with-retry" end test do system "#{bin}/brew-install-with-retry", "--version" end end
- 其中url为brew-install-with-retry.sh脚本的tar包仓库路径(此处上传到了github上),tar包生成命令
tar -czvf brew-install-with-retry.tar.gz brew-install-with-retry.sh
- sha256 为 tar包通过sha256计算的值,命令为
shasum -a 256 brew-install-with-retry-1.0.0.tar.gz
- def install和test部分需要调整为脚本对应的名称信息
- 其中url为brew-install-with-retry.sh脚本的tar包仓库路径(此处上传到了github上),tar包生成命令
2.5. 本地测试formula
首先确保shell脚本是正确的,接下来通过源码方式测试formula(看是否可以正常安装)
brew install --build-from-source brew-install-with-retry.rb
安装成功尝试是否能正常使用
brew-install-with-retry --version
2.6. 提交formula最终验证
-
将formula代码提交到github
-
通过非源码方式安装(这种方式也就时其他人使用时采用的方式)
- 通过
brew tab <user>/tap
添加Tap, 此处我github的user id是leon-fly
brew tab leon-fly/tap
- 使用brew install执行安装
brew install brew-install-with-retry
- 通过
3. 避坑
- 如果是用github托管安装包(tar包),url路径使用带raw的而不是blob,否则会出现sha256码不一致的情况
- 测试formula时可能多次调试,会有重新安装的情况,需要卸载干净,包括cache中的安装包都需要删除。否则也可能出现sha256不一致或者formula没生效的情况