GrabBag/GrabBagPrj/project_meta.sh

351 lines
12 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# 项目注册基础设施
# 所有函数定义。项目配置数据在 project_registry.sh 中。
ALL_PROJECTS=()
declare -A PROJECT_META=()
declare -A PROJECT_COPY_SPECS=()
declare -A PROJECT_OPTIONAL_COPY_SPECS=()
DEFAULT_VERSION_STRING="1.0.0"
DEFAULT_BUILD_NUMBER="1"
# ===== 基础工具 =====
_list_items() { printf '%s\n' "$@"; }
_array_contains() {
local expected=$1; shift
local item
for item in "$@"; do
[ "$item" = "$expected" ] && return 0
done
return 1
}
_trim_leading_spaces() { printf '%s' "${1#"${1%%[![:space:]]*}"}"; }
set_project_meta() { PROJECT_META["$1:$2"]=${3-}; }
get_project_meta() { printf '%s' "${PROJECT_META["$1:$2"]:-}"; }
# ===== 项目查询 =====
list_projects() { _list_items "${ALL_PROJECTS[@]}"; }
is_project() { _array_contains "$1" "${ALL_PROJECTS[@]}"; }
list_projects_by_kind() {
local kind=$1 project
for project in "${ALL_PROJECTS[@]}"; do
[ "$(get_project_meta "$project" package_kind)" = "$kind" ] && printf '%s\n' "$project"
done
}
# ===== 元数据加载 =====
load_version_project_meta() {
local project=$1
is_project "$project" || return 1
VERSION_PROJECT="$project"
VERSION_FILE_REL="$(get_project_meta "$project" version_file_rel)"
VERSION_MACRO="$(get_project_meta "$project" version_macro)"
PUBLISH_NAME="$(get_project_meta "$project" publish_name)"
}
load_package_project_meta() {
local project=$1
is_project "$project" || return 1
PACKAGE_PROJECT="$project"
PACKAGE_NAME="$(get_project_meta "$project" package_name)"
PACKAGE_KIND="$(get_project_meta "$project" package_kind)"
PACKAGE_DESCRIPTION="$(get_project_meta "$project" package_description)"
PACKAGE_COMMENT="$(get_project_meta "$project" package_comment)"
PACKAGE_VERSION_FILE_REL="$(get_project_meta "$project" version_file_rel)"
PACKAGE_VERSION_MACRO="$(get_project_meta "$project" version_macro)"
PACKAGE_BINARY_SOURCE_REL="$(get_project_meta "$project" package_binary_source_rel)"
PACKAGE_BINARY_DEST_REL="$(get_project_meta "$project" package_binary_dest_rel)"
PACKAGE_ICON_SOURCE_REL="$(get_project_meta "$project" package_icon_source_rel)"
PACKAGE_ICON_DEST_REL="$(get_project_meta "$project" package_icon_dest_rel)"
PACKAGE_SERVICE_SOURCE_REL="$(get_project_meta "$project" package_service_source_rel)"
PACKAGE_SERVICE_DEST_REL="$(get_project_meta "$project" package_service_dest_rel)"
PACKAGE_LD_CONF_EXTRA_LINES="$(get_project_meta "$project" package_ld_conf_extra_lines)"
PACKAGE_OPENCV_PROFILE="$(get_project_meta "$project" package_opencv_profile)"
local serialized
serialized="${PROJECT_COPY_SPECS[$project]:-}"
PACKAGE_COPY_SPECS=()
if [ -n "$serialized" ]; then
while IFS= read -r line; do
[ -n "$line" ] && PACKAGE_COPY_SPECS+=("$line")
done <<< "$serialized"
fi
serialized="${PROJECT_OPTIONAL_COPY_SPECS[$project]:-}"
PACKAGE_OPTIONAL_COPY_SPECS=()
if [ -n "$serialized" ]; then
while IFS= read -r line; do
[ -n "$line" ] && PACKAGE_OPTIONAL_COPY_SPECS+=("$line")
done <<< "$serialized"
fi
}
# ===== 版本读取 =====
read_project_version() {
local version_file=$1 version_macro=$2
local candidate value
PROJECT_VERSION="$DEFAULT_VERSION_STRING"
PROJECT_BUILD="$DEFAULT_BUILD_NUMBER"
if [ ! -f "$version_file" ]; then
echo "错误: 版本文件不存在: $version_file" >&2
return 1
fi
for candidate in "${version_macro}_VERSION_STRING" "${version_macro}_APP_VERSION_STRING"; do
value=$(grep -E "^#define[[:space:]]+${candidate}[[:space:]]+\"" "$version_file" | sed -E 's/.*"([^"]+)".*/\1/' | head -n 1 || true)
if [ -n "$value" ]; then PROJECT_VERSION="$value"; break; fi
done
if [ -z "$PROJECT_VERSION" ]; then
echo "错误: 版本文件中未定义版本字符串" >&2
return 1
fi
for candidate in "${version_macro}_BUILD_STRING" "${version_macro}_VERSION_BUILD" "${version_macro}_APP_VERSION_BUILD"; do
value=$(grep -E "^#define[[:space:]]+${candidate}[[:space:]]+\"" "$version_file" | sed -E 's/.*"([^"]+)".*/\1/' | head -n 1 || true)
if [ -n "$value" ]; then PROJECT_BUILD="$value"; break; fi
done
if [ -z "$PROJECT_BUILD" ]; then
echo "错误: 版本文件中未定义构建号" >&2
return 1
fi
return 0
}
# ===== 内部注册函数 =====
_finalize_project_meta() {
local project=$1
local -n meta_ref=$2
if [ -n "${meta_ref[app_dir_rel]}" ]; then
local app_binary_name package_slug
app_binary_name=$(basename "${meta_ref[app_dir_rel]}")
# 服务项目: 先推导 package_name
if [ "${meta_ref[package_kind]}" = "service" ] && [ "${meta_ref[package_name]}" = "$project" ]; then
meta_ref[package_name]="$app_binary_name"
fi
package_slug=$(printf '%s' "${meta_ref[package_name]}" | tr '[:upper:]' '[:lower:]')
: "${meta_ref[version_file_rel]:=${meta_ref[app_dir_rel]}/Version.h}"
: "${meta_ref[package_binary_source_rel]:=GrabBagPrj/buildarm/${meta_ref[app_dir_rel]}/${app_binary_name}}"
if [ -z "${meta_ref[package_binary_dest_rel]}" ]; then
if [ "${meta_ref[package_kind]}" = "service" ]; then
meta_ref[package_binary_dest_rel]="opt/${package_slug}/${app_binary_name}"
else
meta_ref[package_binary_dest_rel]="usr/local/bin/${app_binary_name}"
fi
fi
: "${meta_ref[package_icon_source_rel]:=${meta_ref[app_dir_rel]}/resource/logo.png}"
if [ "${meta_ref[package_kind]}" = "desktop" ]; then
: "${meta_ref[package_icon_dest_rel]:=usr/share/pixmaps/${package_slug}.png}"
fi
if [ "${meta_ref[package_kind]}" = "service" ]; then
: "${meta_ref[package_service_source_rel]:=${meta_ref[app_dir_rel]}/${package_slug}.service}"
: "${meta_ref[package_service_dest_rel]:=opt/${package_slug}/${package_slug}.service}"
fi
fi
# publish_name 自动推导
if [ -z "${meta_ref[publish_name]}" ]; then
if [ "${meta_ref[package_kind]}" = "service" ]; then
meta_ref[publish_name]="${meta_ref[package_name]}"
else
meta_ref[publish_name]="$project"
fi
fi
}
_register_project() {
local project=$1; shift
local -A meta=(
[app_dir_rel]=""
[version_file_rel]=""
[version_macro]=""
[publish_name]=""
[package_name]="$project"
[package_kind]="desktop"
[package_description]=""
[package_comment]=""
[package_binary_source_rel]=""
[package_binary_dest_rel]=""
[package_icon_source_rel]=""
[package_icon_dest_rel]=""
[package_service_source_rel]=""
[package_service_dest_rel]=""
[package_ld_conf_extra_lines]=""
[package_opencv_profile]=""
)
local kv key value
for kv in "$@"; do
key="${kv%%=*}"; value="${kv#*=}"
if [[ -v "meta[$key]" ]]; then
meta["$key"]="$value"
else
echo "Unknown field: ${key} (${project})" >&2; return 1
fi
done
_finalize_project_meta "$project" meta || return 1
ALL_PROJECTS+=("$project")
local k
for k in "${!meta[@]}"; do
set_project_meta "$project" "$k" "${meta[$k]}"
done
PROJECT_COPY_SPECS["$project"]=""
PROJECT_OPTIONAL_COPY_SPECS["$project"]=""
}
_register_desktop_project() {
local project=$1 app_dir_rel=$2 version_macro=$3; shift 3
_register_project "$project" "app_dir_rel=$app_dir_rel" "version_macro=$version_macro" "$@"
}
_register_service_project() {
local project=$1 app_dir_rel=$2 version_macro=$3; shift 3
_register_project "$project" "app_dir_rel=$app_dir_rel" "version_macro=$version_macro" "package_kind=service" "$@"
}
_set_copy_specs() {
local project=$1; shift
PROJECT_COPY_SPECS["$project"]="$(printf '%s\n' "$@")"
}
_set_optional_copy_specs() {
local project=$1; shift
PROJECT_OPTIONAL_COPY_SPECS["$project"]="$(printf '%s\n' "$@")"
}
# ===== 批量注册函数(读取 project_registry.sh 中定义的数组)=====
_parse_kv_overrides() {
# 用法: _parse_kv_overrides fields_array start_index var1 var2 ...
# 从 fields[start_index] 开始解析 key=value赋值给同名变量
local -n _fields=$1
local _start=$2; shift 2
local _allowed_keys=("$@")
local _i _kv _key _value
for (( _i=_start; _i<${#_fields[@]}; _i++ )); do
_kv="$(_trim_leading_spaces "${_fields[$_i]}")"
[ -z "$_kv" ] && continue
_key="${_kv%%=*}"; _value="${_kv#*=}"
local _found=false _ak
for _ak in "${_allowed_keys[@]}"; do
if [ "$_key" = "$_ak" ]; then
eval "$_key=\"\$_value\""
_found=true; break
fi
done
if [ "$_found" = false ]; then
echo "Unknown override key: $_key" >&2
fi
done
}
_register_desktop_projects() {
local entry fields name algo
local app_dir version_macro opencv algo_copy device_copy extra_copy optional_copy ld_conf description comment
for entry in "${DESKTOP_PROJECTS[@]}"; do
IFS=';' read -ra fields <<< "$entry"
name="$(_trim_leading_spaces "${fields[0]}")"
algo="$(_trim_leading_spaces "${fields[1]}")"
# 默认值
app_dir="App/${name}/${name}App"
version_macro=$(printf '%s' "$name" | tr '[:lower:]' '[:upper:]')
opencv="" algo_copy="" device_copy="$COPY_VZNLSDK" extra_copy="" optional_copy=""
ld_conf="" description="" comment=""
_parse_kv_overrides fields 2 \
app_dir version_macro opencv algo_copy device_copy extra_copy optional_copy ld_conf description comment
: "${algo_copy:=glob|AppAlgo/${algo}/Arm/aarch64/*.so|usr/lib}"
# register
local reg_args=()
[ -n "$opencv" ] && reg_args+=("package_opencv_profile=$opencv")
[ -n "$ld_conf" ] && reg_args+=("package_ld_conf_extra_lines=$ld_conf")
[ -n "$description" ] && reg_args+=("package_description=$description")
[ -n "$comment" ] && reg_args+=("package_comment=$comment")
_register_desktop_project "$name" "$app_dir" "$version_macro" "${reg_args[@]}"
# copy specs
local specs=("$algo_copy")
[ -n "$device_copy" ] && [ "$device_copy" != "none" ] && specs+=("$device_copy")
[ -n "$extra_copy" ] && specs+=("$extra_copy")
_set_copy_specs "$name" "${specs[@]}"
# optional copy
if [ -n "$optional_copy" ]; then
_set_optional_copy_specs "$name" "$optional_copy"
elif [ "$device_copy" != "$COPY_VZNLSDK" ]; then
_set_optional_copy_specs "$name" "$COPY_VZNLSDK"
fi
done
}
_register_service_projects() {
local entry fields name algo
local app_suffix version_macro opencv device_copy description
for entry in "${SERVICE_PROJECTS[@]}"; do
IFS=';' read -ra fields <<< "$entry"
name="$(_trim_leading_spaces "${fields[0]}")"
algo="$(_trim_leading_spaces "${fields[1]}")"
# 默认值
app_suffix="Server" version_macro="" opencv=""
device_copy="$COPY_VZNLSDK" description=""
_parse_kv_overrides fields 2 \
app_suffix version_macro opencv device_copy description
: "${version_macro:=$(printf '%s' "$name" | tr '[:lower:]' '[:upper:]')}"
# register
local reg_args=()
[ -n "$opencv" ] && reg_args+=("package_opencv_profile=$opencv")
[ -n "$description" ] && reg_args+=("package_description=$description")
_register_service_project "$name" "App/${name}/${name}${app_suffix}" "$version_macro" "${reg_args[@]}"
_set_copy_specs "$name" "glob|AppAlgo/${algo}/Arm/aarch64/*.so|usr/lib" "$device_copy"
# 自动检测 config 目录
local app_dir="App/${name}/${name}${app_suffix}"
if [ -d "${SCRIPT_DIR}/../${app_dir}/config" ]; then
local pkg_name
pkg_name=$(get_project_meta "$name" package_name)
local slug
slug=$(printf '%s' "$pkg_name" | tr '[:upper:]' '[:lower:]')
_set_optional_copy_specs "$name" "dir|${app_dir}/config|opt/${slug}/config"
fi
done
}