223 lines
8.7 KiB
Bash
223 lines
8.7 KiB
Bash
#!/usr/bin/env bash
|
||
set -e
|
||
cdir=$(cd "$(dirname "$0")" && pwd)
|
||
cd "$cdir"
|
||
|
||
echo "=== Pipeline App Build ==="
|
||
|
||
# 1. Create venv
|
||
if [ ! -d py3 ]; then
|
||
python3 -m venv py3
|
||
fi
|
||
source py3/bin/activate
|
||
|
||
# 2. Install foundation packages (clone to pkgs)
|
||
mkdir -p pkgs
|
||
for m in apppublic sqlor ahserver bricks-for-python xls2ddl rbac appbase dapi; do
|
||
echo "install $m ..."
|
||
cd "$cdir/pkgs"
|
||
if [ ! -d "$m" ]; then
|
||
git clone https://git.opencomputing.cn/yumoqing/$m || echo "SKIP: $m clone failed"
|
||
fi
|
||
if [ -d "$m" ]; then
|
||
cd "$m"
|
||
"$cdir/py3/bin/pip" install . 2>&1 | tail -1
|
||
fi
|
||
cd "$cdir"
|
||
done
|
||
|
||
# 3. Build bricks frontend
|
||
cd "$cdir/pkgs"
|
||
if [ ! -d bricks ]; then
|
||
git clone https://git.opencomputing.cn/yumoqing/bricks || true
|
||
fi
|
||
if [ ! -f bricks/dist/bricks.js ]; then
|
||
mkdir -p bricks/dist
|
||
if [ -d bricks/bricks ]; then
|
||
cd bricks/bricks
|
||
bash build.sh 2>&1 | tail -3
|
||
cd "$cdir/pkgs"
|
||
fi
|
||
fi
|
||
# Link dist to wwwroot
|
||
rm -rf "$cdir/wwwroot/bricks" 2>/dev/null
|
||
ln -sf "$cdir/pkgs/bricks/dist" "$cdir/wwwroot/bricks"
|
||
echo "bricks: $(readlink "$cdir/wwwroot/bricks")"
|
||
|
||
# 4. Move local business modules into pkgs/
|
||
cd "$cdir"
|
||
for mod in pipeline_core pipeline_ops pipeline_dist; do
|
||
if [ -d "$mod" ]; then
|
||
mv "$mod" "pkgs/$mod"
|
||
fi
|
||
done
|
||
|
||
# 5. Install business modules (clone external, local already in pkgs)
|
||
for mod in pipeline-sdlc showcase evaluate pipeline-service pipeline-task tenant app_audit product_management discount pricing unipay smssend accounting; do
|
||
cd "$cdir/pkgs"
|
||
if [ ! -d "$mod" ]; then
|
||
git clone https://git.opencomputing.cn/yumoqing/$mod || echo "SKIP: $mod"
|
||
fi
|
||
cd "$cdir"
|
||
done
|
||
|
||
# 6. pip install all modules from pkgs/(pipeline-service 是普通 install 非 editable,部署必 pull+pip install 都做)
|
||
for mod in pipeline_core pipeline_ops pipeline_dist pipeline-sdlc showcase pipeline-service tenant app_audit product_management discount pricing unipay smssend accounting; do
|
||
if [ -d "pkgs/$mod" ]; then
|
||
"$cdir/py3/bin/pip" install "pkgs/$mod/" 2>&1 | tail -1
|
||
fi
|
||
done
|
||
|
||
# 6c. Runtime deps: pymupdf(office-text-extract 技能的 pdf 提取脚本依赖)
|
||
"$cdir/py3/bin/pip" install pymupdf 2>&1 | tail -1
|
||
|
||
# 6b. Deploy skills: global(public skills) + packs(skill pack manifests)
|
||
if [ -d "pkgs/pipeline_core/skills_library" ]; then
|
||
mkdir -p "$cdir/skills/global"
|
||
# 公共技能:预置技能全量复制到 global(所有 agent 默认加载,目录层按触发词匹配,正文按需 load_skill)
|
||
cp -r "pkgs/pipeline_core/skills_library/all/." "$cdir/skills/global/"
|
||
# 技能集清单(manifest 引用 global 里的技能名)
|
||
rm -rf "$cdir/skills/packs"
|
||
cp -r "pkgs/pipeline_core/skills_library/packs" "$cdir/skills/packs"
|
||
# 产线技能:pipelines/{pipeline_id}/common/ + roles/{role}/(SDLC 等产线默认规范,loader 按此路径扫描)
|
||
rm -rf "$cdir/skills/pipelines"
|
||
if [ -d "pkgs/pipeline_core/skills_library/pipelines" ]; then
|
||
cp -r "pkgs/pipeline_core/skills_library/pipelines" "$cdir/skills/pipelines"
|
||
echo " skills: pipelines(产线技能) 已部署,共 $(ls "$cdir/skills/pipelines" | wc -l) 个产线"
|
||
fi
|
||
echo " skills: global(公共技能)+packs(技能集) 已部署,global 共 $(ls "$cdir/skills/global" | wc -l) 个技能"
|
||
fi
|
||
|
||
# 7. Regenerate CRUD from json for all pipeline modules
|
||
for mod in appbase pipeline_core pipeline_ops pipeline_dist pipeline-sdlc rbac dapi accounting; do
|
||
json_dir="pkgs/$mod/json"
|
||
models_dir="pkgs/$mod/models"
|
||
wwwroot_dir="pkgs/$mod/wwwroot"
|
||
if [ -d "$json_dir" ] && ls "$json_dir"/*.json >/dev/null 2>&1; then
|
||
cd "$json_dir"
|
||
"$cdir/py3/bin/xls2ui" -m "../models" -o "../wwwroot" "$mod" *.json 2>&1 | grep -c 'handle' | xargs -I{} echo " xls2ui $mod: {} tables"
|
||
cd "$cdir"
|
||
fi
|
||
done
|
||
|
||
|
||
# 8. Link module wwwroot directories (symlinks from pkgs/)
|
||
for mod in pipeline-sdlc showcase tenant pipeline_core pipeline_ops pipeline_dist appbase app_audit product_management discount pricing unipay rbac dapi accounting; do
|
||
src="pkgs/$mod/wwwroot"
|
||
dst="wwwroot/$mod"
|
||
if [ -d "$src" ]; then
|
||
rm -rf "$dst" 2>/dev/null
|
||
ln -sf "../pkgs/$mod/wwwroot" "$dst"
|
||
echo " wwwroot: $mod linked"
|
||
fi
|
||
done
|
||
# pipeline_task has no separate module
|
||
mkdir -p wwwroot/pipeline_task
|
||
|
||
# 9. Sync password_key from Sage (not databases — those are app-specific)
|
||
if [ -f /d/apitest/sage/conf/config.json ]; then
|
||
python3 -c "
|
||
import json
|
||
cs=json.load(open('/d/apitest/sage/conf/config.json'))
|
||
c=json.load(open('$cdir/conf/config.json'))
|
||
c['password_key']=cs.get('password_key','')
|
||
json.dump(c,open('$cdir/conf/config.json','w'),ensure_ascii=False,indent=2)
|
||
print(' config: password_key synced')
|
||
"
|
||
fi
|
||
|
||
# 10. Create runtime dirs
|
||
mkdir -p "$cdir/logs" "$cdir/files" "$cdir/conf" "$cdir/bin"
|
||
|
||
# 10.5 Install bwrap (zero-root: 系统已有则复用,否则 apt download + dpkg -x)
|
||
if [ ! -x "$cdir/bin/bwrap" ]; then
|
||
if command -v bwrap >/dev/null 2>&1; then
|
||
cp "$(command -v bwrap)" "$cdir/bin/bwrap" 2>/dev/null || true
|
||
else
|
||
tmpd=$(mktemp -d)
|
||
( cd "$tmpd" && apt download bubblewrap >/dev/null 2>&1 && dpkg -x bubblewrap*.deb . && cp usr/bin/bwrap "$cdir/bin/bwrap" ) 2>/dev/null || true
|
||
rm -rf "$tmpd"
|
||
fi
|
||
fi
|
||
if [ -x "$cdir/bin/bwrap" ]; then
|
||
echo " bwrap: $("$cdir/bin/bwrap" --version 2>/dev/null | head -1)"
|
||
else
|
||
echo " WARN: bwrap not available (deploy sandbox will degrade to dir isolation)"
|
||
fi
|
||
|
||
# 10.8 Install Node(office 技能脚本依赖,无 sudo:官方预编译二进制)
|
||
# 解压到 bin/nodejs/,symlink node/npm/npx 到 bin/(start.sh 已把 $cdir/bin 加进 PATH)
|
||
NODE_VER="v22.23.2"
|
||
if [ ! -x "$cdir/bin/nodejs/bin/node" ]; then
|
||
echo " node: downloading $NODE_VER (linux-x64) ..."
|
||
tmpn=$(mktemp -d)
|
||
if curl -sL --max-time 180 "https://nodejs.org/dist/$NODE_VER/node-$NODE_VER-linux-x64.tar.xz" -o "$tmpn/node.tar.xz" && \
|
||
tar -xJf "$tmpn/node.tar.xz" -C "$tmpn"; then
|
||
mkdir -p "$cdir/bin/nodejs"
|
||
cp -a "$tmpn/node-$NODE_VER-linux-x64/." "$cdir/bin/nodejs/"
|
||
else
|
||
echo " WARN: node 下载失败(office 技能脚本不可用)"
|
||
fi
|
||
rm -rf "$tmpn"
|
||
fi
|
||
ln -sf nodejs/bin/node "$cdir/bin/node"
|
||
ln -sf nodejs/bin/npm "$cdir/bin/npm"
|
||
ln -sf nodejs/bin/npx "$cdir/bin/npx"
|
||
if [ -x "$cdir/bin/node" ]; then
|
||
echo " node: $("$cdir/bin/node" --version)"
|
||
fi
|
||
|
||
# 6. Fix auto-assign created_by in CRUD dspys (xls2ui overwritten)
|
||
for d in sd_projects sd_iterations; do
|
||
for t in add update; do
|
||
f="$cdir/wwwroot/pipeline-sdlc/$d/${t}_${d}.dspy"
|
||
[ -f "$f" ] && grep -q 'created_by' "$f" || sed -i "s/ns\['org_id'\] = userorgid/ns['org_id'] = userorgid\nns['created_by'] = userorgid/" "$f"
|
||
done
|
||
done
|
||
|
||
# 6b. Inject session-current-project filter into generated get dspys (迭代/Bug/测试用例 用会话当前项目,无项目报错)
|
||
if [ -f "$cdir/scripts/inject_project_filter.py" ]; then
|
||
"$cdir/py3/bin/python" "$cdir/scripts/inject_project_filter.py" "$cdir/wwwroot/pipeline-sdlc" || echo " WARN: inject_project_filter.py failed"
|
||
fi
|
||
|
||
|
||
# 10.6 Create module tables (models -> DDL -> execute)
|
||
echo "=== Module table creation ==="
|
||
if [ -f "$cdir/scripts/create_tables.py" ]; then
|
||
"$cdir/py3/bin/python" "$cdir/scripts/create_tables.py" || echo " WARN: create_tables.py failed (DB not ready?)"
|
||
else
|
||
echo " WARN: scripts/create_tables.py not found"
|
||
fi
|
||
|
||
# 10.7 Import module init data (appcodes dictionaries)
|
||
echo "=== Module init data import ==="
|
||
if [ -f "$cdir/scripts/import_init.py" ]; then
|
||
"$cdir/py3/bin/python" "$cdir/scripts/import_init.py" || echo " WARN: import_init.py failed (DB not ready?)"
|
||
else
|
||
echo " WARN: scripts/import_init.py not found"
|
||
fi
|
||
|
||
# 11. Import RBAC permissions from conf/rp.json (r:p 数据 -> permission + rolepermission)
|
||
echo "=== RBAC permission import ==="
|
||
if [ -f "$cdir/scripts/import_rp.py" ]; then
|
||
"$cdir/py3/bin/python" "$cdir/scripts/import_rp.py" || echo " WARN: import_rp.py failed (DB not ready?)"
|
||
else
|
||
echo " WARN: scripts/import_rp.py not found"
|
||
fi
|
||
|
||
# 11.5 汇率自动获取定时任务(每日 8:00 抓取中国银行外汇牌价)
|
||
# accounting 模块 fetch_forex_rates.dspy:USD/JPY/GBP → CNY,幂等写入 exchange_rate
|
||
if [ -f "$cdir/pkgs/accounting/wwwroot/api/fetch_forex_rates.dspy" ]; then
|
||
forex_cron="0 8 * * * curl -s http://localhost:9090/accounting/api/fetch_forex_rates.dspy"
|
||
cc=$(crontab -l 2>/dev/null || true)
|
||
if ! echo "$cc" | grep -Fq "fetch_forex_rates"; then
|
||
(echo "$cc"; echo "$forex_cron") | crontab -
|
||
echo " cron: 汇率任务已添加(每日 8:00)"
|
||
else
|
||
echo " cron: 汇率任务已存在,未重复添加"
|
||
fi
|
||
fi
|
||
|
||
chmod +x "$cdir/start.sh" "$cdir/stop.sh" 2>/dev/null || true
|
||
echo "=== Build complete ==="
|