mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-09-21 01:18:02 +00:00
feat(scripts): 批量打插件包(.hmap)供 release 发布
## 问题
release 此前**只发 homed/waiter 二进制与 hmapdev 工具链,不发插件包**(主仓 20 个
release、本仓的 release 都核实过,0 个 .hmap)。用户要用任何一个插件,都得:
1. 装 Go 1.25 + 网络拉依赖
2. 装 hmapdev 工具链
3. 进 example/<插件>/ 逐个 `hmapdev build`
而 `hmapdev build` **不是可选项**:5 个 example(deepsearch / luademo / vanblog /
vikunja / weather)连 `main.go` 都没有,直接 `go build` 会死在
「function main is undeclared in the main package」——入口是 hmapdev 现生成的。
所以「开箱可用」名不副实。本脚本把这一步前置到发布流程里。
## 用法
```bash
./scripts/build_plugin_bundles.sh # 全部 21 个
./scripts/build_plugin_bundles.sh weather qq # 指定
OUT=../dist/plugins ./scripts/build_plugin_bundles.sh
```
产出 `.hmap` + `SHA256SUMS.plugins`,可直接作为 release 附件。
## 实现要点(三处是踩过才写对的)
1. **产物有三种形态**,不能只认 `_bundle.hmap`:
- `<name>_bundle.hmap` 多平台 bundle(`plg.json` 的 `bundle: true`)
- `<name>_<os>_<arch>.hmap` 单平台(**qq** 的 plg.json 是 `bundle: false`,
与其余 20 个不一致)
- `<name>_lua.hmap` Lua 插件(**luademo**,不编译 Go)
脚本按形态标注,发布时能一眼看出是哪种。
2. **`set -e` 下不能用 `[ -z "$x" ] && x=$(ls ...)` 做兜底**:
一次 `ls` 无匹配(退出码 2)就会让整个子 shell 直接退出,后面的兜底根本走不到。
实测表现是「只有 qq 和 luademo 失败」——因为正是它俩没有 `_bundle.hmap`。
改成 `for` 循环 + `|| true`。
3. **参数拼错要报错,不能静默跳过**(否则以为打了实际没打)。
## 验证
- 21/21 构建成功,合计约 150 MB(bundle 含 linux/amd64 + darwin/amd64;
不含 windows 是**策略**——homed 已放弃 Windows 原生,源码注释有说明)
- 每个包内部结构核对:含 plugin.json、含内核认得的入口、当前平台可得
This commit is contained in:
130
scripts/build_plugin_bundles.sh
Executable file
130
scripts/build_plugin_bundles.sh
Executable file
@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env bash
|
||||
# 为 SDK 仓的 example 插件批量打 .hmap 包,产出可直接随 release 发布的插件包。
|
||||
#
|
||||
# 背景:release 此前只发 homed/waiter 二进制与 hmapdev 工具链,**不发插件包**。
|
||||
# 用户要用某个插件,得自己装 Go 1.25、拉依赖、装 hmapdev、逐个 build —— 这是
|
||||
# 「开箱即用」名不副实的根源。本脚本把这一步前置到发布流程里。
|
||||
#
|
||||
# 用法:
|
||||
# ./build_plugin_bundles.sh # 全部 example
|
||||
# ./build_plugin_bundles.sh weather qq memo # 指定插件
|
||||
# OUT=../dist/plugins ./build_plugin_bundles.sh
|
||||
#
|
||||
# 环境:
|
||||
# HMAPDEV hmapdev 可执行文件(默认取 PATH 上的 hmapdev)
|
||||
# OUT 产物目录(默认 <script>/../../dist/plugins)
|
||||
# JOBS 并行度(默认 CPU 核数)
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
EX_DIR="$(cd "$SCRIPT_DIR/../example" && pwd)"
|
||||
SDK_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
OUT="${OUT:-$(cd "$SDK_DIR/.." && pwd)/dist/plugins}"
|
||||
HMAPDEV="${HMAPDEV:-hmapdev}"
|
||||
|
||||
command -v "$HMAPDEV" >/dev/null 2>&1 || {
|
||||
echo "error: 找不到 hmapdev(设 HMAPDEV=/path/to/hmapdev 或用 'hmapdev sdk install' 装)" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$OUT"
|
||||
|
||||
# 收集候选插件:有 plg.json 才可构建
|
||||
all=()
|
||||
for d in "$EX_DIR"/*/; do
|
||||
n="$(basename "$d")"
|
||||
[ -f "$d/plg.json" ] || continue
|
||||
all+=("$n")
|
||||
done
|
||||
|
||||
# 参数指定则取交集(并校验名字有效,避免拼错静默跳过)
|
||||
if [ "$#" -gt 0 ]; then
|
||||
want=("$@")
|
||||
sel=()
|
||||
for w in "${want[@]}"; do
|
||||
found=""
|
||||
for n in "${all[@]}"; do [ "$n" = "$w" ] && found=1 && break; done
|
||||
[ -n "$found" ] || { echo "error: 未知插件 '$w'(可用: ${all[*]})" >&2; exit 1; }
|
||||
sel+=("$w")
|
||||
done
|
||||
all=("${sel[@]}")
|
||||
fi
|
||||
|
||||
echo "=== 打包 ${#all[@]} 个插件 → $OUT ==="
|
||||
echo " hmapdev: $("$HMAPDEV" --version 2>/dev/null | head -1 || echo "$HMAPDEV")"
|
||||
|
||||
build_one() {
|
||||
local name="$1"
|
||||
local dir="$EX_DIR/$name"
|
||||
local log="$OUT/.$name.log"
|
||||
|
||||
# hmapdev build 必须在插件目录内跑(它读当前目录的 plg.json)
|
||||
if ! (cd "$dir" && "$HMAPDEV" build >"$log" 2>&1); then
|
||||
echo " ✗ $name 构建失败(见 $log)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 产物有三种形态,不能只认 _bundle.hmap:
|
||||
# 1) <name>_bundle.hmap 多平台 bundle(plg.json 里 bundle: true)
|
||||
# 2) <name>_<os>_<arch>.hmap 单平台(bundle 关掉时,如 qq)
|
||||
# 3) <name>_lua.hmap Lua 插件(不编译 Go,如 luademo)
|
||||
#
|
||||
# 注意用 if 而非 `[ -z ] && found=$(ls...)`:在 set -e 下,
|
||||
# 一次 ls 无匹配就会让整个子 shell 直接退出,根本走不到后面的兜底。
|
||||
local found=""
|
||||
local cand
|
||||
for pat in "$dir"/dist/*_bundle.hmap "$dir"/dist/*.hmap "$dir"/*_bundle.hmap; do
|
||||
if [ -z "$found" ]; then
|
||||
cand="$(ls -t $pat 2>/dev/null | head -1 || true)"
|
||||
[ -n "$cand" ] && found="$cand"
|
||||
fi
|
||||
done
|
||||
if [ -z "$found" ]; then
|
||||
echo " ✗ $name 未产出 .hmap(见 $log)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cp -f "$found" "$OUT/"
|
||||
local sz bn
|
||||
bn="$(basename "$found")"
|
||||
sz="$(stat -c%s "$OUT/$bn" 2>/dev/null || stat -f%z "$OUT/$bn")"
|
||||
# 标注形态:单平台/Lua 包与多平台 bundle 不同,发布时要能一眼看出
|
||||
local tag=""
|
||||
case "$bn" in
|
||||
*_bundle.hmap) tag="bundle" ;;
|
||||
*_lua.hmap) tag="lua " ;;
|
||||
*) tag="单平台" ;;
|
||||
esac
|
||||
printf " ✓ %-16s %7.1f MB %s\n" "$name" "$(echo "$sz" | awk '{print $1/1048576}')" "$tag"
|
||||
rm -f "$log"
|
||||
}
|
||||
|
||||
fail=0
|
||||
pids=()
|
||||
for n in "${all[@]}"; do
|
||||
# 有 nproc 就限并发,没有就串行
|
||||
if command -v nproc >/dev/null 2>&1; then
|
||||
while [ "$(jobs -rp | wc -l)" -ge "${JOBS:-$(nproc)}" ]; do wait -n 2>/dev/null || true; done
|
||||
fi
|
||||
( build_one "$n" ) &
|
||||
pids+=($!)
|
||||
done
|
||||
for p in "${pids[@]}"; do wait "$p" || fail=$((fail+1)); done
|
||||
|
||||
echo
|
||||
echo "=== 产出 ==="
|
||||
ls -la "$OUT"/*.hmap 2>/dev/null | awk '{printf " %-46s %8.1f MB\n", $9, $5/1048576}' || echo " (无)"
|
||||
|
||||
# 汇总校验和,便于随 release 一起发布与验证
|
||||
if ls "$OUT"/*.hmap >/dev/null 2>&1; then
|
||||
( cd "$OUT" && sha256sum ./*.hmap > SHA256SUMS.plugins )
|
||||
echo
|
||||
echo "=== 校验和 → $OUT/SHA256SUMS.plugins ==="
|
||||
cat "$OUT/SHA256SUMS.plugins" | sed 's/^/ /'
|
||||
fi
|
||||
|
||||
if [ "$fail" -gt 0 ]; then
|
||||
echo
|
||||
echo "error: $fail 个插件构建失败" >&2
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user