107 lines
3.6 KiB
Bash
107 lines
3.6 KiB
Bash
#!/usr/bin/env bash
|
||
#
|
||
# check-proto-sync.sh — 检查 .proto 和 .pb.go 的 rawDesc 是否一致
|
||
#
|
||
# 工作原理:从 .proto 文件提取字段数量,从 .pb.go 的 Go struct 提取字段数量,
|
||
# 如果 struct 的字段比 proto 的字段多(说明手动添加了字段没有重新生成),则报错。
|
||
#
|
||
# 用法:
|
||
# ./check-proto-sync.sh # 检查所有 proto 文件
|
||
# ./check-proto-sync.sh --fix # 如果有 protoc,自动重新生成
|
||
|
||
set -e
|
||
|
||
ROOT=$(dirname "$0")/..
|
||
PROTO_DIR="$ROOT/pkg/rpc/protos"
|
||
PB_DIR="$ROOT/pkg/rpc/pb"
|
||
ERRORS=0
|
||
|
||
echo "Checking proto <-> pb.go sync ..."
|
||
|
||
# 对每个 .proto 文件,检查 message 中的字段数量是否和 .pb.go 一致
|
||
for proto_file in "$PROTO_DIR"/*.proto "$PROTO_DIR"/models/*.proto; do
|
||
[ -f "$proto_file" ] || continue
|
||
|
||
base=$(basename "$proto_file" .proto)
|
||
pb_file="$PB_DIR/${base}.pb.go"
|
||
|
||
[ -f "$pb_file" ] || continue
|
||
|
||
# 从 .proto 提取每个 message 的字段数(格式: "MessageName:N")
|
||
# 只计算顶层 message 的直接字段(= N 格式的行)
|
||
current_msg=""
|
||
declare -A proto_fields
|
||
while IFS= read -r line; do
|
||
# 匹配 message 声明
|
||
if [[ "$line" =~ ^[[:space:]]*message[[:space:]]+([A-Za-z0-9_]+) ]]; then
|
||
current_msg="${BASH_REMATCH[1]}"
|
||
proto_fields["$current_msg"]=0
|
||
fi
|
||
# 匹配字段声明(type name = N;)
|
||
if [ -n "$current_msg" ] && [[ "$line" =~ =[[:space:]]*[0-9]+\; ]]; then
|
||
proto_fields["$current_msg"]=$(( ${proto_fields["$current_msg"]} + 1 ))
|
||
fi
|
||
# message 结束
|
||
if [ -n "$current_msg" ] && [[ "$line" =~ ^[[:space:]]*\} ]]; then
|
||
current_msg=""
|
||
fi
|
||
done < "$proto_file"
|
||
|
||
# 从 .pb.go 提取每个 struct 的 protobuf 字段数
|
||
declare -A pbgo_fields
|
||
current_struct=""
|
||
while IFS= read -r line; do
|
||
if [[ "$line" =~ ^type[[:space:]]+([A-Za-z0-9_]+)[[:space:]]+struct ]]; then
|
||
current_struct="${BASH_REMATCH[1]}"
|
||
pbgo_fields["$current_struct"]=0
|
||
fi
|
||
if [ -n "$current_struct" ] && [[ "$line" =~ protobuf:\" ]]; then
|
||
pbgo_fields["$current_struct"]=$(( ${pbgo_fields["$current_struct"]} + 1 ))
|
||
fi
|
||
if [ -n "$current_struct" ] && [[ "$line" =~ ^\} ]]; then
|
||
current_struct=""
|
||
fi
|
||
done < "$pb_file"
|
||
|
||
# 比较
|
||
for msg in "${!proto_fields[@]}"; do
|
||
proto_count=${proto_fields["$msg"]}
|
||
pbgo_count=${pbgo_fields["$msg"]:-0}
|
||
|
||
if [ "$pbgo_count" -gt "$proto_count" ] 2>/dev/null; then
|
||
echo " [WARN] $base: struct '$msg' has $pbgo_count fields in .pb.go but only $proto_count in .proto (hand-edited?)"
|
||
ERRORS=$((ERRORS + 1))
|
||
elif [ "$pbgo_count" -lt "$proto_count" ] 2>/dev/null; then
|
||
echo " [WARN] $base: struct '$msg' has $pbgo_count fields in .pb.go but $proto_count in .proto (needs regeneration)"
|
||
ERRORS=$((ERRORS + 1))
|
||
fi
|
||
done
|
||
|
||
unset proto_fields
|
||
unset pbgo_fields
|
||
declare -A proto_fields
|
||
declare -A pbgo_fields
|
||
done
|
||
|
||
if [ "$ERRORS" -gt 0 ]; then
|
||
echo ""
|
||
echo "Found $ERRORS proto sync issue(s)."
|
||
echo "Fix: install protoc and run 'cd EdgeCommon/build && ./build.sh'"
|
||
|
||
if [ "$1" = "--fix" ]; then
|
||
if command -v protoc &>/dev/null; then
|
||
echo "Regenerating ..."
|
||
cd "$(dirname "$0")"
|
||
./build.sh
|
||
echo "Done. Please review and commit the changes."
|
||
else
|
||
echo "protoc not found, cannot auto-fix."
|
||
exit 1
|
||
fi
|
||
else
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "All proto files are in sync. OK"
|
||
fi
|