374 lines
11 KiB
Bash
Executable File
374 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Netrans 安装脚本(增量安装)
|
||
# 功能:
|
||
# 1. 对比安装状态快照,只执行必要的步骤
|
||
# 2. 安装 Python 依赖(仅在 requirements.txt 变化时)
|
||
# 3. 安装 acuity(仅在 vendor 变化时)
|
||
# 4. 安装 netrans(pip install -e,几乎零开销)
|
||
# 5. 配置环境变量 PATH、VIV_SDK_PATH 和 NETRANS_PYTHON
|
||
|
||
set -e
|
||
|
||
# ── 前置检查:Python 版本和系统架构 ──────────────────────
|
||
PYTHON_CMD="python3"
|
||
PIP_CMD="$PYTHON_CMD -m pip"
|
||
python_version=$($PYTHON_CMD -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')
|
||
NETRANS_PYTHON=$($PYTHON_CMD -c 'import sys; print(sys.executable)')
|
||
required_version="3.10"
|
||
if [ "$(printf '%s\n' "$required_version" "$python_version" | sort -V | head -n1)" != "$required_version" ]; then
|
||
echo "错误: Python版本需要 >= $required_version,当前版本: $python_version"
|
||
exit 1
|
||
fi
|
||
|
||
arch=$(uname -m)
|
||
if [ "$arch" != "x86_64" ]; then
|
||
echo "错误: Netrans 仅支持 x86_64 架构,当前架构: $arch"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✓ 前置检查通过: Python $python_version, $arch"
|
||
|
||
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
SCRIPT_DIR="$CURRENT_DIR/script"
|
||
INSTALL_STATE="$CURRENT_DIR/.install_state"
|
||
VIV_SDK_PATH="$CURRENT_DIR/vendor/viv_sdk/VivanteIDE5.8.2/cmdtools"
|
||
BASHRC="$HOME/.bashrc"
|
||
|
||
require_file() {
|
||
local file="$1"
|
||
local name="$2"
|
||
|
||
if [ ! -f "$file" ]; then
|
||
echo "错误: 缺少 ${name}: $file"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
require_dir() {
|
||
local dir="$1"
|
||
local name="$2"
|
||
|
||
if [ ! -d "$dir" ]; then
|
||
echo "错误: 缺少 ${name}: $dir"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
hash_files_under() {
|
||
local dir="$1"
|
||
|
||
if [ ! -d "$dir" ]; then
|
||
echo "missing"
|
||
return
|
||
fi
|
||
|
||
find "$dir" -type f \
|
||
! -path "*/__pycache__/*" \
|
||
! -name "*.pyc" \
|
||
! -name "*.pyo" \
|
||
-print0 2>/dev/null \
|
||
| sort -z \
|
||
| xargs -0 -r md5sum 2>/dev/null \
|
||
| md5sum \
|
||
| cut -d' ' -f1
|
||
}
|
||
|
||
hash_tree_metadata() {
|
||
local dir="$1"
|
||
|
||
if [ ! -d "$dir" ]; then
|
||
echo "missing"
|
||
return
|
||
fi
|
||
|
||
find "$dir" -type f \
|
||
! -path "*/__pycache__/*" \
|
||
! -name "*.pyc" \
|
||
! -name "*.pyo" \
|
||
-printf "%P %s %T@\n" 2>/dev/null \
|
||
| sort \
|
||
| md5sum \
|
||
| cut -d' ' -f1
|
||
}
|
||
|
||
find_acuity_whl() {
|
||
find "$CURRENT_DIR/vendor" -maxdepth 1 -type f -name "acuity-*.whl" 2>/dev/null \
|
||
| sort \
|
||
| head -1
|
||
}
|
||
|
||
hash_files() {
|
||
local files=()
|
||
local file
|
||
|
||
for file in "$@"; do
|
||
if [ -f "$file" ]; then
|
||
files+=("$file")
|
||
fi
|
||
done
|
||
|
||
if [ ${#files[@]} -eq 0 ]; then
|
||
echo "missing"
|
||
return
|
||
fi
|
||
|
||
md5sum "${files[@]}" | sort | md5sum | cut -d' ' -f1
|
||
}
|
||
|
||
load_install_state() {
|
||
local file="$1"
|
||
local key
|
||
local value
|
||
|
||
installed_version=""
|
||
vendor_state=""
|
||
requirements_hash=""
|
||
setup_hash=""
|
||
|
||
if [ ! -f "$file" ]; then
|
||
return 1
|
||
fi
|
||
|
||
while IFS='=' read -r key value; do
|
||
case "$key" in
|
||
""|\#*) continue ;;
|
||
esac
|
||
|
||
value=$(printf '%s' "$value" | tr -d '[:space:]')
|
||
|
||
case "$key" in
|
||
installed_version)
|
||
if [[ "$value" =~ ^[A-Za-z0-9._+-]+$ ]]; then
|
||
installed_version="$value"
|
||
fi
|
||
;;
|
||
vendor_state)
|
||
if [[ "$value" =~ ^([A-Fa-f0-9]+|missing)$ ]]; then
|
||
vendor_state="$value"
|
||
fi
|
||
;;
|
||
requirements_hash)
|
||
if [[ "$value" =~ ^([A-Fa-f0-9]+|missing)$ ]]; then
|
||
requirements_hash="$value"
|
||
fi
|
||
;;
|
||
setup_hash)
|
||
if [[ "$value" =~ ^([A-Fa-f0-9]+|missing)$ ]]; then
|
||
setup_hash="$value"
|
||
fi
|
||
;;
|
||
esac
|
||
done < "$file"
|
||
|
||
return 0
|
||
}
|
||
|
||
read_version_meta() {
|
||
local key="$1"
|
||
local file="$CURRENT_DIR/VERSION"
|
||
|
||
if [ ! -f "$file" ]; then
|
||
return
|
||
fi
|
||
|
||
local value
|
||
value=$(grep -E "^${key}=" "$file" | head -1 | cut -d'=' -f2- | tr -d '[:space:]')
|
||
if [ -n "$value" ]; then
|
||
echo "$value"
|
||
return
|
||
fi
|
||
|
||
# Backward compatibility with the old single-line VERSION format.
|
||
if [ "$key" = "VERSION" ]; then
|
||
head -1 "$file" | tr -d '[:space:]'
|
||
fi
|
||
}
|
||
|
||
write_shell_env() {
|
||
local rc_file="$1"
|
||
local tmp_file
|
||
|
||
mkdir -p "$(dirname "$rc_file")"
|
||
touch "$rc_file"
|
||
tmp_file=$(mktemp)
|
||
|
||
awk '
|
||
/^# >>> Netrans environment >>>$/ { skip=1; next }
|
||
/^# <<< Netrans environment <<<$/{ skip=0; next }
|
||
skip { next }
|
||
/^# Netrans 命令行工具路径$/ { skip_next=1; next }
|
||
/^# Netrans Vivante SDK 路径$/ { skip_next=1; next }
|
||
/^# Netrans Python 解释器$/ { skip_next=1; next }
|
||
skip_next && /^export PATH=.*\/script"/ { skip_next=0; next }
|
||
skip_next && /^export VIV_SDK_PATH="/ { skip_next=0; next }
|
||
skip_next && /^export NETRANS_PYTHON="/ { skip_next=0; next }
|
||
{ skip_next=0; print }
|
||
' "$rc_file" > "$tmp_file"
|
||
|
||
cat >> "$tmp_file" << EOF
|
||
|
||
# >>> Netrans environment >>>
|
||
export PATH="\$PATH:$SCRIPT_DIR"
|
||
export VIV_SDK_PATH="$VIV_SDK_PATH"
|
||
export NETRANS_PYTHON="$NETRANS_PYTHON"
|
||
# <<< Netrans environment <<<
|
||
EOF
|
||
|
||
mv "$tmp_file" "$rc_file"
|
||
}
|
||
|
||
echo "========================================"
|
||
echo " Netrans 安装脚本"
|
||
echo "========================================"
|
||
|
||
# ── 检查源码目录结构 ──────────────────────────────────
|
||
require_file "$CURRENT_DIR/VERSION" "版本文件"
|
||
require_file "$CURRENT_DIR/requirements.txt" "依赖清单"
|
||
require_file "$CURRENT_DIR/setup.py" "Python 包配置"
|
||
require_dir "$CURRENT_DIR/src/netrans" "netrans 源码目录"
|
||
require_dir "$SCRIPT_DIR" "脚本目录"
|
||
require_dir "$CURRENT_DIR/vendor" "vendor 目录"
|
||
require_dir "$VIV_SDK_PATH" "Vivante SDK cmdtools 目录"
|
||
ACUITY_WHL=$(find_acuity_whl)
|
||
if [ -z "$ACUITY_WHL" ]; then
|
||
echo "错误: 未找到 acuity whl 文件: $CURRENT_DIR/vendor/acuity-*.whl"
|
||
exit 1
|
||
fi
|
||
|
||
# ── 读取上次安装状态 ──────────────────────────────────
|
||
if load_install_state "$INSTALL_STATE"; then
|
||
echo ""
|
||
echo "[预检] 上次安装版本: ${installed_version:-未知}"
|
||
else
|
||
echo ""
|
||
echo "[预检] 首次安装,将执行全量安装"
|
||
installed_version=""
|
||
vendor_state=""
|
||
requirements_hash=""
|
||
setup_hash=""
|
||
fi
|
||
|
||
# ── 读取强制重装门禁 ──────────────────────────────────
|
||
force_since=""
|
||
force_since=$(read_version_meta "FORCE_REINSTALL_SINCE")
|
||
|
||
# ── 读取当前版本 ──────────────────────────────────────
|
||
current_version=""
|
||
current_version=$(read_version_meta "VERSION")
|
||
if [ -z "$current_version" ]; then
|
||
echo "错误: VERSION 文件中未找到 VERSION"
|
||
exit 1
|
||
fi
|
||
|
||
# ── 计算当前指纹 ──────────────────────────────────────
|
||
current_vendor_state=$(hash_tree_metadata "$CURRENT_DIR/vendor")
|
||
current_requirements_hash=$(md5sum "$CURRENT_DIR/requirements.txt" 2>/dev/null | cut -d' ' -f1)
|
||
current_setup_hash=$( (hash_files_under "$CURRENT_DIR/script"; hash_files "$CURRENT_DIR/setup.sh"; printf '%s\n%s\n%s\n' "$SCRIPT_DIR" "$VIV_SDK_PATH" "$NETRANS_PYTHON") | md5sum | cut -d' ' -f1)
|
||
|
||
# ── 判断是否需要全量重装 ──────────────────────────────
|
||
need_full_reinstall=false
|
||
|
||
if [ -z "$installed_version" ]; then
|
||
need_full_reinstall=true
|
||
elif [ -n "$force_since" ] && [ "$installed_version" != "$force_since" ]; then
|
||
# 版本比较:如果 installed_version < force_since,需要全量重装
|
||
# 使用 sort -V 做版本号排序比较
|
||
if printf '%s\n%s\n' "$installed_version" "$force_since" | sort -V | head -1 | grep -q "^$installed_version$" && \
|
||
[ "$installed_version" != "$force_since" ]; then
|
||
echo ""
|
||
echo "⚠ 当前版本 $installed_version < 强制重装门禁 $force_since,将执行全量安装"
|
||
need_full_reinstall=true
|
||
fi
|
||
fi
|
||
|
||
if $need_full_reinstall; then
|
||
# 重置所有指纹,强制全量安装
|
||
vendor_state=""
|
||
requirements_hash=""
|
||
setup_hash=""
|
||
fi
|
||
|
||
# ── 判断各部件的安装需求 ──────────────────────────────
|
||
need_deps=false
|
||
need_acuity=false
|
||
need_setup_config=false
|
||
|
||
if [ "$vendor_state" != "$current_vendor_state" ]; then
|
||
need_acuity=true
|
||
fi
|
||
|
||
if [ "$requirements_hash" != "$current_requirements_hash" ]; then
|
||
need_deps=true
|
||
fi
|
||
|
||
if [ "$setup_hash" != "$current_setup_hash" ]; then
|
||
need_setup_config=true
|
||
fi
|
||
|
||
# ── 步骤 1: 安装 Python 依赖 ──────────────────────────
|
||
echo ""
|
||
if $need_deps || $need_full_reinstall; then
|
||
echo "[1/4] 安装 Python 依赖..."
|
||
$PIP_CMD install -r "$CURRENT_DIR/requirements.txt"
|
||
echo "✓ 依赖安装完成"
|
||
else
|
||
echo "[1/4] Python 依赖 (跳过,无变化)"
|
||
fi
|
||
|
||
# ── 步骤 2: 安装 acuity ───────────────────────────────
|
||
echo ""
|
||
|
||
if $need_acuity || $need_full_reinstall; then
|
||
echo "[2/4] 安装 acuity..."
|
||
if [ -n "$ACUITY_WHL" ] && [ -f "$ACUITY_WHL" ]; then
|
||
$PIP_CMD install "$ACUITY_WHL" --no-deps --force-reinstall
|
||
echo "✓ acuity 安装完成"
|
||
else
|
||
echo "✗ 未找到 acuity whl 文件: $CURRENT_DIR/vendor/acuity-*.whl"
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "[2/4] acuity (跳过,vendor 无变化)"
|
||
fi
|
||
|
||
# ── 步骤 3: 安装 netrans ──────────────────────────────
|
||
echo ""
|
||
echo "[3/4] 安装 netrans (pip install -e)..."
|
||
$PIP_CMD install -e "$CURRENT_DIR"
|
||
echo "✓ netrans 安装完成"
|
||
|
||
# ── 步骤 4: 配置环境变量 ──────────────────────────────
|
||
echo ""
|
||
|
||
if $need_setup_config || $need_full_reinstall; then
|
||
echo "[4/4] 配置环境变量..."
|
||
write_shell_env "$BASHRC"
|
||
echo " ✓ PATH、VIV_SDK_PATH 和 NETRANS_PYTHON 已写入 $BASHRC"
|
||
else
|
||
echo "[4/4] 环境变量 (跳过,无变化)"
|
||
fi
|
||
|
||
# ── 写入安装状态快照 ──────────────────────────────────
|
||
cat > "$INSTALL_STATE" << EOF
|
||
# Netrans 安装状态快照(自动生成,勿手动编辑)
|
||
installed_version=$current_version
|
||
vendor_state=$current_vendor_state
|
||
requirements_hash=$current_requirements_hash
|
||
setup_hash=$current_setup_hash
|
||
EOF
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
echo " 安装完成!"
|
||
echo "========================================"
|
||
echo ""
|
||
if $need_setup_config || $need_full_reinstall; then
|
||
echo "请执行以下命令使配置生效:"
|
||
echo " source ~/.bashrc"
|
||
echo ""
|
||
fi
|
||
echo "验证安装:"
|
||
echo " python -c \"import netrans; print(netrans.__version__)\""
|
||
echo " netrans --help"
|