This commit implements a complete migration from JSON-based configuration to .env environment variables, providing better security and flexibility. Key Changes: - Add python-dotenv dependency for environment variable support - Create config/env_loader.py with type conversion utilities - Add from_env() class methods to all config dataclasses - Update ConfigLoader to prioritize environment variables - Add save_to_env() method for .env file management - Implement database connection factory pattern - Add base DAO and connection classes for better abstraction - Support both SQL Server and MySQL with unified interface - Create migration script (scripts/migrate_to_env.py) - Update GUI to read/write .env files - Add comprehensive migration documentation New Files: - config/env_loader.py - Environment variable loader - db/base_connection.py - Base database connection interface - db/base_dao.py - Base DAO with common utilities - db/connection_factory.py - Factory for creating connections - db/mysql_connection.py - MySQL-specific connection - db/sqlserver_connection.py - SQL Server-specific connection - db/table_name_converter.py - SQL dialect converter - scripts/migrate_to_env.py - Configuration migration tool - docs/ENV_MIGRATION.md - Complete migration guide - .env.example - Environment variable template Testing: - Verified MySQL connection (8.0.44) - Tested all DAO operations - Confirmed 150 tables accessible - Validated configuration loading Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
227 lines
6.9 KiB
Python
227 lines
6.9 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
配置迁移脚本
|
|
|
|
将现有的 JSON 配置文件迁移到 .env 环境变量文件
|
|
"""
|
|
import os
|
|
import sys
|
|
import json
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
# 添加项目根目录到 sys.path
|
|
project_root = Path(__file__).parent.parent
|
|
sys.path.insert(0, str(project_root))
|
|
|
|
from config.schema import AppConfig
|
|
|
|
|
|
def migrate_json_to_env(
|
|
json_file: str = "config/user_settings.json",
|
|
env_file: str = ".env",
|
|
backup: bool = True
|
|
) -> bool:
|
|
"""
|
|
迁移 JSON 配置到 .env 文件
|
|
|
|
Args:
|
|
json_file: JSON 配置文件路径
|
|
env_file: .env 文件路径
|
|
backup: 是否备份原 JSON 文件
|
|
|
|
Returns:
|
|
迁移是否成功
|
|
"""
|
|
json_path = project_root / json_file
|
|
env_path = project_root / env_file
|
|
|
|
# 检查 JSON 文件是否存在
|
|
if not json_path.exists():
|
|
print(f"❌ JSON 配置文件不存在: {json_path}")
|
|
print(f"💡 提示: 如果这是首次运行,请复制 .env.example 到 .env 并填入配置")
|
|
return False
|
|
|
|
# 检查 .env 文件是否已存在
|
|
if env_path.exists():
|
|
response = input(f"⚠️ .env 文件已存在: {env_path}\n是否覆盖? (y/N): ")
|
|
if response.lower() != 'y':
|
|
print("❌ 迁移已取消")
|
|
return False
|
|
|
|
# 备份现有的 .env 文件
|
|
backup_path = env_path.with_suffix(".env.backup")
|
|
shutil.copy(env_path, backup_path)
|
|
print(f"✅ 已备份现有 .env 文件到: {backup_path}")
|
|
|
|
try:
|
|
# 读取 JSON 配置
|
|
print(f"📖 读取 JSON 配置: {json_path}")
|
|
with open(json_path, "r", encoding="utf-8") as f:
|
|
json_data = json.load(f)
|
|
|
|
# 使用 ConfigLoader 将字典转换为配置对象
|
|
from config.loader import ConfigLoader
|
|
config = ConfigLoader._dict_to_config(json_data)
|
|
|
|
# 保存到 .env 文件
|
|
print(f"💾 保存配置到 .env 文件: {env_path}")
|
|
success = ConfigLoader.save_to_env(config, env_file)
|
|
|
|
if not success:
|
|
print("❌ 保存 .env 文件失败")
|
|
return False
|
|
|
|
# 备份原 JSON 文件
|
|
if backup:
|
|
backup_path = json_path.with_suffix(".json.backup")
|
|
shutil.copy(json_path, backup_path)
|
|
print(f"✅ 已备份 JSON 配置到: {backup_path}")
|
|
|
|
print("\n✅ 配置迁移成功!")
|
|
print(f"\n📝 新配置文件: {env_path}")
|
|
print(f"📦 备份文件: {backup_path if backup else '无'}")
|
|
print("\n💡 提示:")
|
|
print(" 1. 请检查 .env 文件中的配置是否正确")
|
|
print(" 2. 确保 .env 文件不会被提交到版本控制")
|
|
print(" 3. 可以删除原 JSON 配置文件: " + str(json_path))
|
|
|
|
return True
|
|
|
|
except json.JSONDecodeError as e:
|
|
print(f"❌ JSON 解析失败: {e}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"❌ 迁移失败: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
def create_env_from_example(
|
|
example_file: str = ".env.example",
|
|
env_file: str = ".env"
|
|
) -> bool:
|
|
"""
|
|
从 .env.example 创建 .env 文件
|
|
|
|
Args:
|
|
example_file: .env.example 文件路径
|
|
env_file: .env 文件路径
|
|
|
|
Returns:
|
|
创建是否成功
|
|
"""
|
|
example_path = project_root / example_file
|
|
env_path = project_root / env_file
|
|
|
|
if not example_path.exists():
|
|
print(f"❌ .env.example 文件不存在: {example_path}")
|
|
return False
|
|
|
|
if env_path.exists():
|
|
response = input(f"⚠️ .env 文件已存在: {env_path}\n是否覆盖? (y/N): ")
|
|
if response.lower() != 'y':
|
|
print("❌ 操作已取消")
|
|
return False
|
|
|
|
try:
|
|
shutil.copy(example_path, env_path)
|
|
print(f"✅ 已从 {example_file} 创建 {env_file}")
|
|
print("\n💡 提示:")
|
|
print(" 1. 请编辑 .env 文件,填入实际的配置值")
|
|
print(" 2. 特别注意敏感信息(密码、密钥等)")
|
|
print(" 3. 确保 .env 文件不会被提交到版本控制")
|
|
return True
|
|
except Exception as e:
|
|
print(f"❌ 创建失败: {e}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""主函数"""
|
|
print("=" * 60)
|
|
print("🔄 配置迁移工具 - JSON → .env")
|
|
print("=" * 60)
|
|
|
|
# 检查命令行参数
|
|
if len(sys.argv) > 1:
|
|
command = sys.argv[1].lower()
|
|
|
|
if command == "from-example":
|
|
# 从 .env.example 创建
|
|
print("\n📋 模式: 从 .env.example 创建配置文件")
|
|
example_file = sys.argv[2] if len(sys.argv) > 2 else ".env.example"
|
|
env_file = sys.argv[3] if len(sys.argv) > 3 else ".env"
|
|
create_env_from_example(example_file, env_file)
|
|
return
|
|
|
|
elif command == "migrate":
|
|
# 从 JSON 迁移
|
|
print("\n📋 模式: 从 JSON 配置迁移")
|
|
json_file = sys.argv[2] if len(sys.argv) > 2 else "config/user_settings.json"
|
|
env_file = sys.argv[3] if len(sys.argv) > 3 else ".env"
|
|
migrate_json_to_env(json_file, env_file)
|
|
return
|
|
|
|
elif command == "help":
|
|
print("""
|
|
用法:
|
|
python scripts/migrate_to_env.py <命令> [参数]
|
|
|
|
命令:
|
|
migrate [json_file] [env_file] 从 JSON 配置迁移到 .env
|
|
from-example [example] [env_file] 从 .env.example 创建配置文件
|
|
help 显示此帮助信息
|
|
|
|
示例:
|
|
python scripts/migrate_to_env.py migrate
|
|
python scripts/migrate_to_env.py migrate config/user_settings.json .env
|
|
python scripts/migrate_to_env.py from-example
|
|
python scripts/migrate_to_env.py from-example .env.example .env.local
|
|
""")
|
|
return
|
|
|
|
# 交互模式
|
|
print("\n请选择操作:")
|
|
print(" 1. 从 JSON 配置迁移到 .env")
|
|
print(" 2. 从 .env.example 创建配置文件")
|
|
print(" 3. 退出")
|
|
|
|
choice = input("\n请输入选项 (1-3): ").strip()
|
|
|
|
if choice == "1":
|
|
json_file = input("JSON 配置文件路径 (默认: config/user_settings.json): ").strip()
|
|
if not json_file:
|
|
json_file = "config/user_settings.json"
|
|
|
|
env_file = input(".env 文件路径 (默认: .env): ").strip()
|
|
if not env_file:
|
|
env_file = ".env"
|
|
|
|
backup_choice = input("是否备份原 JSON 文件? (Y/n): ").strip().lower()
|
|
backup = backup_choice != 'n'
|
|
|
|
migrate_json_to_env(json_file, env_file, backup)
|
|
|
|
elif choice == "2":
|
|
example_file = input(".env.example 文件路径 (默认: .env.example): ").strip()
|
|
if not example_file:
|
|
example_file = ".env.example"
|
|
|
|
env_file = input(".env 文件路径 (默认: .env): ").strip()
|
|
if not env_file:
|
|
env_file = ".env"
|
|
|
|
create_env_from_example(example_file, env_file)
|
|
|
|
elif choice == "3":
|
|
print("👋 再见!")
|
|
else:
|
|
print("❌ 无效的选项")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|