145 lines
5.8 KiB
Bash
145 lines
5.8 KiB
Bash
#!/bin/bash
|
||
# pipeline-opportunity 一键部署脚本(在宿主应用根目录执行或从本目录定位宿主)。
|
||
# 职责:建表(运行期禁止 schema 变更,建表只在部署期)+ 种子数据(appcodes + pipelines 产线记录)
|
||
# + wwwroot 软链 + pip install 本包。
|
||
# 参考模式:pipeline-bidding/build.sh。
|
||
set -e
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
||
# 定位宿主应用根目录(含 wwwroot + py3)
|
||
APP_ROOT=""
|
||
for candidate in "$SCRIPT_DIR/../../pipeline-app" "$SCRIPT_DIR/../.." "$HOME/work/pipeline/pipeline-app"; do
|
||
if [ -d "$candidate/wwwroot" ] && [ -d "$candidate/py3" ]; then
|
||
APP_ROOT="$(cd "$candidate" && pwd)"
|
||
break
|
||
fi
|
||
done
|
||
if [ -z "$APP_ROOT" ]; then
|
||
echo "ERROR: host app (pipeline-app) root not found"
|
||
exit 1
|
||
fi
|
||
PYTHON="$APP_ROOT/py3/bin/python"
|
||
echo "Host app root: $APP_ROOT"
|
||
|
||
# ── 1. 建表(幂等:CREATE TABLE IF NOT EXISTS)──
|
||
cd "$SCRIPT_DIR"
|
||
"$PYTHON" - "$APP_ROOT" <<'PYEOF'
|
||
import re
|
||
ddl = open('mysql.ddl.sql', encoding='utf-8').read()
|
||
ddl = re.sub(r'drop table if exists (\w+);', '', ddl)
|
||
ddl = re.sub(r'CREATE TABLE (\w+)\s*\(', r'CREATE TABLE IF NOT EXISTS \1 (', ddl)
|
||
open('/tmp/pipeline_opportunity_ddl.sql', 'w', encoding='utf-8').write(ddl)
|
||
print('DDL prepared:', ddl.count('CREATE TABLE IF NOT EXISTS'), 'tables')
|
||
PYEOF
|
||
|
||
"$PYTHON" - "$APP_ROOT" <<'PYEOF'
|
||
import sys, os, subprocess
|
||
sys.path.insert(0, os.getcwd())
|
||
from appPublic.jsonConfig import getConfig
|
||
from appPublic.aes import aes_decode_b64
|
||
cfg = getConfig(sys.argv[1], {'workdir': sys.argv[1]})
|
||
kw = cfg.databases['pipeline'].kwargs
|
||
pwd = aes_decode_b64(cfg.password_key, kw.password)
|
||
with open('/tmp/pipeline_opportunity_ddl.sql', 'rb') as f:
|
||
r = subprocess.run(['mysql', '-h', str(kw.host), '-P', str(kw.port),
|
||
'-u', str(kw.user), '-p%s' % pwd, str(kw.db)],
|
||
stdin=f, capture_output=True)
|
||
if r.returncode == 0:
|
||
print('tables applied')
|
||
else:
|
||
print('ERROR:', r.stderr.decode('utf-8', 'replace').strip()[:300])
|
||
sys.exit(1)
|
||
PYEOF
|
||
|
||
# ── 2. 种子数据:appcodes 字典 + pipelines 产线记录(数据源 init/data.json,幂等)──
|
||
cd "$APP_ROOT"
|
||
"$PYTHON" - "$SCRIPT_DIR" "$APP_ROOT" <<'PYEOF'
|
||
import sys, os, json, asyncio
|
||
CDIR = sys.argv[1]
|
||
sys.path.insert(0, os.getcwd())
|
||
from appPublic.jsonConfig import getConfig
|
||
from sqlor.dbpools import DBPools
|
||
from appPublic.uniqueID import getID
|
||
|
||
data = json.load(open(os.path.join(CDIR, 'init', 'data.json')))
|
||
|
||
async def seed():
|
||
config = getConfig(sys.argv[2], {'workdir': sys.argv[2]})
|
||
db = DBPools(config.databases)
|
||
async with db.sqlorContext('pipeline') as sor:
|
||
for pl in data.get('pipelines', []):
|
||
recs = await sor.sqlExe("SELECT id FROM pipelines WHERE id=${i}$", {"i": pl['id']})
|
||
if not recs:
|
||
await sor.C('pipelines', {
|
||
'id': pl['id'], 'name': pl['name'],
|
||
'description': pl.get('description', ''),
|
||
'pipeline_type': pl.get('pipeline_type', 'opportunity'),
|
||
'version': '1.0.0', 'status': pl.get('status', 'published'),
|
||
'org_id': pl.get('org_id', '0'), 'created_by': 'system',
|
||
})
|
||
print('pipeline registered:', pl['id'])
|
||
for ac in data.get('appcodes', []):
|
||
pid = ac['parentid']
|
||
rows = await sor.R('appcodes', {'id': pid})
|
||
if not rows:
|
||
await sor.C('appcodes', {'id': pid, 'name': ac.get('parentname', pid),
|
||
'hierarchy_flg': '0'})
|
||
for item in ac.get('items', []):
|
||
chk = await sor.sqlExe(
|
||
"SELECT id FROM appcodes_kv WHERE parentid=${p}$ AND k=${k}$",
|
||
{'p': pid, 'k': item['k']})
|
||
if not chk:
|
||
await sor.C('appcodes_kv', {'id': getID(), 'parentid': pid,
|
||
'k': item['k'], 'v': item['v']})
|
||
await sor.sqlExe("COMMIT", {})
|
||
print('seeded %d code groups' % len(data.get('appcodes', [])))
|
||
|
||
asyncio.run(seed())
|
||
PYEOF
|
||
|
||
# ── 2b. params 种子:挖掘算法参数(幂等:已存在不覆盖,运行期可在 params 表调)──
|
||
cd "$APP_ROOT"
|
||
"$PYTHON" - "$SCRIPT_DIR" "$APP_ROOT" <<'PYEOF'
|
||
import sys, os, json, asyncio
|
||
CDIR = sys.argv[1]
|
||
sys.path.insert(0, os.getcwd())
|
||
from appPublic.jsonConfig import getConfig
|
||
from sqlor.dbpools import DBPools
|
||
from appPublic.uniqueID import getID
|
||
|
||
data = json.load(open(os.path.join(CDIR, 'init', 'data.json')))
|
||
params_seed = data.get('params', [])
|
||
|
||
async def seed_params():
|
||
if not params_seed:
|
||
return
|
||
config = getConfig(sys.argv[2], {'workdir': sys.argv[2]})
|
||
db = DBPools(config.databases)
|
||
n = 0
|
||
async with db.sqlorContext('pipeline') as sor:
|
||
for pitem in params_seed:
|
||
chk = await sor.sqlExe(
|
||
"SELECT id FROM params WHERE params_name=${n}$", {"n": pitem['name']})
|
||
if not chk:
|
||
await sor.C('params', {'id': getID(),
|
||
'params_name': pitem['name'],
|
||
'params_value': str(pitem['value'])})
|
||
n += 1
|
||
await sor.sqlExe("COMMIT", {})
|
||
print('params seeded:', n, '(existing kept)')
|
||
|
||
asyncio.run(seed_params())
|
||
PYEOF
|
||
|
||
# ── 3. wwwroot 软链 + pip install ──
|
||
rm -f "$APP_ROOT/wwwroot/pipeline-opportunity"
|
||
ln -sf "$SCRIPT_DIR/wwwroot" "$APP_ROOT/wwwroot/pipeline-opportunity"
|
||
echo "wwwroot linked: pipeline-opportunity"
|
||
|
||
"$APP_ROOT/py3/bin/pip" install "$SCRIPT_DIR/" 2>&1 | tail -1
|
||
|
||
echo "pipeline-opportunity module deploy complete."
|
||
echo "后续(宿主负责):app 入口 import load_pipeline_opportunity;RBAC 用 scripts/load_path.py。"
|
||
echo "爬虫平台接入配置:appbase params 表设 tender_api_base / tender_api_token(默认 http://192.168.16.2:9085)。"
|