#!/usr/bin/env python3 """ 存储后端数据迁移脚本 用法: python scripts/migrate_storage.py --from json --to postgres python scripts/migrate_storage.py --from postgres --to git python scripts/migrate_storage.py --export accounts.json python scripts/migrate_storage.py --import accounts.json """ import argparse import json import os import sys from pathlib import Path # 添加项目根目录到 Python 路径 sys.path.insert(0, str(Path(__file__).resolve().parents[1])) DATA_DIR = Path(__file__).resolve().parents[1] / "data" from services.storage.factory import create_storage_backend def export_to_json(output_file: str): """导出当前存储后端的数据到 JSON 文件""" print(f"[migrate] Exporting data to {output_file}") DATA_DIR.mkdir(parents=True, exist_ok=True) storage = create_storage_backend(DATA_DIR) accounts = storage.load_accounts() output_path = Path(output_file) output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text( json.dumps(accounts, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", ) print(f"[migrate] Exported {len(accounts)} accounts to {output_file}") def import_from_json(input_file: str): """从 JSON 文件导入数据到当前存储后端""" print(f"[migrate] Importing data from {input_file}") DATA_DIR.mkdir(parents=True, exist_ok=True) input_path = Path(input_file) if not input_path.exists(): print(f"[migrate] Error: File not found: {input_file}") sys.exit(1) try: accounts = json.loads(input_path.read_text(encoding="utf-8")) if not isinstance(accounts, list): print(f"[migrate] Error: Invalid JSON format, expected array") sys.exit(1) except json.JSONDecodeError as e: print(f"[migrate] Error: Invalid JSON: {e}") sys.exit(1) storage = create_storage_backend(DATA_DIR) storage.save_accounts(accounts) print(f"[migrate] Imported {len(accounts)} accounts") def migrate_data(from_backend: str, to_backend: str): """从一个存储后端迁移到另一个""" print(f"[migrate] Migrating from {from_backend} to {to_backend}") DATA_DIR.mkdir(parents=True, exist_ok=True) # 保存原始环境变量 original_backend = os.environ.get("STORAGE_BACKEND") try: # 从源后端读取数据 os.environ["STORAGE_BACKEND"] = from_backend from_storage = create_storage_backend(DATA_DIR) accounts = from_storage.load_accounts() print(f"[migrate] Loaded {len(accounts)} accounts from {from_backend}") # 写入目标后端 os.environ["STORAGE_BACKEND"] = to_backend to_storage = create_storage_backend(DATA_DIR) to_storage.save_accounts(accounts) print(f"[migrate] Saved {len(accounts)} accounts to {to_backend}") print(f"[migrate] Migration completed successfully!") finally: # 恢复原始环境变量 if original_backend: os.environ["STORAGE_BACKEND"] = original_backend elif "STORAGE_BACKEND" in os.environ: del os.environ["STORAGE_BACKEND"] def main(): parser = argparse.ArgumentParser( description="ChatGPT2API 存储后端数据迁移工具", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" 示例: # 从 JSON 迁移到 PostgreSQL python scripts/migrate_storage.py --from json --to postgres # 从 PostgreSQL 迁移到 Git python scripts/migrate_storage.py --from postgres --to git # 导出当前数据到 JSON 文件 python scripts/migrate_storage.py --export backup.json # 从 JSON 文件导入数据 python scripts/migrate_storage.py --import backup.json 环境变量: STORAGE_BACKEND - 存储后端类型 (json, sqlite, postgres, git) DATABASE_URL - 数据库连接字符串 GIT_REPO_URL - Git 仓库地址 GIT_TOKEN - Git 访问令牌 """ ) parser.add_argument( "--from", dest="from_backend", choices=["json", "sqlite", "postgres", "git"], help="源存储后端", ) parser.add_argument( "--to", dest="to_backend", choices=["json", "sqlite", "postgres", "git"], help="目标存储后端", ) parser.add_argument( "--export", dest="export_file", metavar="FILE", help="导出数据到 JSON 文件", ) parser.add_argument( "--import", dest="import_file", metavar="FILE", help="从 JSON 文件导入数据", ) args = parser.parse_args() # 检查参数 if args.from_backend and args.to_backend: migrate_data(args.from_backend, args.to_backend) elif args.export_file: export_to_json(args.export_file) elif args.import_file: import_from_json(args.import_file) else: parser.print_help() sys.exit(1) if __name__ == "__main__": main()