from __future__ import annotations
|
|
import argparse
|
import getpass
|
import json
|
import os
|
import re
|
from pathlib import Path
|
|
import pymysql
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
DEFAULT_SEED_DIR = ROOT / "data" / "mysql_seed_20260624"
|
|
|
def split_sql(sql: str) -> list[str]:
|
parts: list[str] = []
|
buff: list[str] = []
|
for line in sql.splitlines():
|
buff.append(line)
|
if line.strip().endswith(";"):
|
stmt = "\n".join(buff).strip()
|
if stmt:
|
parts.append(stmt[:-1] if stmt.endswith(";") else stmt)
|
buff = []
|
tail = "\n".join(buff).strip()
|
if tail:
|
parts.append(tail)
|
return parts
|
|
|
def get_password(args: argparse.Namespace) -> str:
|
if args.password:
|
return args.password
|
if os.environ.get("DARKLINE_MYSQL_PASSWORD"):
|
return os.environ["DARKLINE_MYSQL_PASSWORD"]
|
return getpass.getpass("MySQL password: ")
|
|
|
def connect_without_db(args: argparse.Namespace, password: str):
|
return pymysql.connect(
|
host=args.host,
|
port=args.port,
|
user=args.user,
|
password=password,
|
charset="utf8mb4",
|
autocommit=True,
|
)
|
|
|
def connect_with_db(args: argparse.Namespace, password: str):
|
return pymysql.connect(
|
host=args.host,
|
port=args.port,
|
user=args.user,
|
password=password,
|
database=args.database,
|
charset="utf8mb4",
|
autocommit=True,
|
)
|
|
|
def main() -> None:
|
parser = argparse.ArgumentParser(description="Import darkline seed data into local MySQL.")
|
parser.add_argument("--host", default=os.environ.get("DARKLINE_MYSQL_HOST", "127.0.0.1"))
|
parser.add_argument("--port", type=int, default=int(os.environ.get("DARKLINE_MYSQL_PORT", "3306")))
|
parser.add_argument("--user", default=os.environ.get("DARKLINE_MYSQL_USER", "root"))
|
parser.add_argument("--password", default=None)
|
parser.add_argument("--database", default=os.environ.get("DARKLINE_MYSQL_DATABASE", "tianxia"))
|
parser.add_argument("--seed-dir", default=str(DEFAULT_SEED_DIR))
|
parser.add_argument("--create-database", action="store_true")
|
args = parser.parse_args()
|
|
seed_dir = Path(args.seed_dir)
|
password = get_password(args)
|
|
if args.create_database:
|
conn = connect_without_db(args, password)
|
with conn.cursor() as cur:
|
cur.execute(
|
f"CREATE DATABASE IF NOT EXISTS `{args.database}` "
|
"CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci"
|
)
|
conn.close()
|
|
conn = connect_with_db(args, password)
|
with conn.cursor() as cur:
|
schema_sql = (seed_dir / "schema.sql").read_text(encoding="utf-8")
|
for stmt in split_sql(schema_sql):
|
cur.execute(stmt)
|
|
table_order = json.loads((seed_dir / "table_order.json").read_text(encoding="utf-8"))
|
imported_counts = {}
|
for table in table_order:
|
jsonl_path = seed_dir / "tables" / f"{table}.jsonl"
|
rows = [
|
json.loads(line)
|
for line in jsonl_path.read_text(encoding="utf-8").splitlines()
|
if line.strip()
|
]
|
if not rows:
|
imported_counts[table] = 0
|
continue
|
columns = list(rows[0].keys())
|
col_sql = ", ".join(f"`{c}`" for c in columns)
|
placeholders = ", ".join(["%s"] * len(columns))
|
sql = f"REPLACE INTO `{table}` ({col_sql}) VALUES ({placeholders})"
|
cur.executemany(sql, [[row.get(c) for c in columns] for row in rows])
|
imported_counts[table] = len(rows)
|
|
verify_counts = {}
|
for table in table_order:
|
cur.execute(f"SELECT COUNT(*) FROM `{table}`")
|
verify_counts[table] = cur.fetchone()[0]
|
|
conn.close()
|
print(
|
json.dumps(
|
{
|
"import_status": "PASS",
|
"database": args.database,
|
"seed_dir": str(seed_dir),
|
"imported_counts": imported_counts,
|
"verify_counts": verify_counts,
|
},
|
ensure_ascii=False,
|
indent=2,
|
)
|
)
|
|
|
if __name__ == "__main__":
|
main()
|