上传文件至 /

This commit is contained in:
hujinyang 2026-01-19 08:01:13 +00:00
parent e51b895bc8
commit 93309fb762
5 changed files with 2066 additions and 0 deletions

10
__init__.py Normal file
View File

@ -0,0 +1,10 @@
"""
配置编辑器模块
"""
__version__ = "1.3"
__author__ = "Config Editor"
from main_window import ConfigEditor
__all__ = ['ConfigEditor']

724
build.sh Normal file
View File

@ -0,0 +1,724 @@
#!/bin/bash
# 打包脚本:将配置编辑器项目打包成 deb 包
set -e # 遇到错误时退出
# ==================== 配置区域 ====================
APP_NAME="config-editor"
APP_VERSION="1.3"
APP_DESCRIPTION="CE编辑器"
MAINTAINER="hjy <hujinyang@jspwkj.com.cn>"
ARCHITECTURE="amd64"
DEPENDENCIES="python3, python3-venv, python3-pip"
PYTHON_VERSION="3.8"
VENV_PATH="/opt/$APP_NAME/venv"
APP_INSTALL_PATH="/opt/$APP_NAME"
# =================================================
echo "========================================"
echo "开始构建 $APP_NAME (版本 $APP_VERSION)"
echo "========================================"
echo "将使用虚拟环境: $VENV_PATH"
# 1. 清理之前的构建
echo "1. 清理之前的构建..."
rm -rf build/ dist/ deb_dist/ *.egg-info/ 2>/dev/null || true
rm -rf /tmp/$APP_NAME-* 2>/dev/null || true
# 2. 创建构建目录结构
echo "2. 创建构建目录结构..."
BUILD_ROOT="/tmp/${APP_NAME}-${APP_VERSION}"
DEBIAN_DIR="$BUILD_ROOT/DEBIAN"
APP_DIR="$BUILD_ROOT$APP_INSTALL_PATH"
BIN_DIR="$BUILD_ROOT/usr/bin"
DESKTOP_DIR="$BUILD_ROOT/usr/share/applications"
ICON_DIR="$BUILD_ROOT/usr/share/icons/hicolor"
MIME_DIR="$BUILD_ROOT/usr/share/mime/packages"
VAR_LIB_DIR="$BUILD_ROOT/var/lib/$APP_NAME"
# 清理并重新创建目录
rm -rf "$BUILD_ROOT"
mkdir -p "$DEBIAN_DIR"
mkdir -p "$APP_DIR"
mkdir -p "$BIN_DIR"
mkdir -p "$DESKTOP_DIR"
mkdir -p "$ICON_DIR/48x48/apps"
mkdir -p "$ICON_DIR/64x64/apps"
mkdir -p "$ICON_DIR/128x128/apps"
mkdir -p "$MIME_DIR"
mkdir -p "$VAR_LIB_DIR"
# 3. 复制项目文件
echo "3. 复制项目文件..."
cp -r *.py "$APP_DIR/"
cp -r login/ "$APP_DIR/"
cp -r requirements.txt "$APP_DIR/"
# 清理不必要的文件
find "$APP_DIR" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
find "$APP_DIR" -name "*.pyc" -delete 2>/dev/null || true
find "$APP_DIR" -name ".DS_Store" -delete 2>/dev/null || true
# 4. 创建启动脚本(使用虚拟环境中的 Python
echo "4. 创建启动脚本..."
cat > "$BIN_DIR/$APP_NAME" << EOF
#!/bin/bash
# 配置编辑器启动脚本(使用虚拟环境)
# 应用程序安装路径
APP_DIR="$APP_INSTALL_PATH"
VENV_PATH="$VENV_PATH"
# 检查虚拟环境是否存在
if [ ! -f "\$VENV_PATH/bin/activate" ]; then
echo "错误: 虚拟环境不存在。请重新安装应用程序。"
exit 1
fi
# 激活虚拟环境并运行程序
cd "\$APP_DIR"
source "\$VENV_PATH/bin/activate"
exec python main.py "\$@"
EOF
chmod +x "$BIN_DIR/$APP_NAME"
# 5. 创建桌面入口文件
echo "5. 创建桌面入口文件..."
cat > "$DESKTOP_DIR/$APP_NAME.desktop" << EOF
[Desktop Entry]
Name=Config Editor
Name[zh_CN]=配置编辑器
Comment=$APP_DESCRIPTION
Comment[zh_CN]=用于管理和编辑配置文件
Exec=$APP_NAME
Icon=$APP_NAME
Terminal=false
Type=Application
Categories=Development;Utility;
StartupNotify=true
Keywords=config;editor;settings;configuration;
MimeType=application/x-python;
EOF
# 6. 创建图标(如果没有提供图标,则生成一个简单的)
echo "6. 创建图标..."
if [ -f "logo.png" ]; then
# 如果有现有图标,使用它
cp logo.png "$ICON_DIR/48x48/apps/$APP_NAME.png"
cp logo.png "$ICON_DIR/64x64/apps/$APP_NAME.png"
cp logo.png "$ICON_DIR/128x128/apps/$APP_NAME.png"
else
# 如果没有图标,创建一个简单的占位符
echo "未找到图标文件,创建简单图标..."
# 使用 ImageMagick 创建图标(如果可用)
if command -v convert &> /dev/null; then
# 创建 48x48 图标
convert -size 48x48 xc:#2196F3 \
-fill white -pointsize 24 -gravity center -annotate 0 "CE" \
"$ICON_DIR/48x48/apps/$APP_NAME.png"
# 创建 64x64 图标
convert -size 64x64 xc:#2196F3 \
-fill white -pointsize 32 -gravity center -annotate 0 "CE" \
"$ICON_DIR/64x64/apps/$APP_NAME.png"
# 创建 128x128 图标
convert -size 128x128 xc:#2196F3 \
-fill white -pointsize 48 -gravity center -annotate 0 "CE" \
"$ICON_DIR/128x128/apps/$APP_NAME.png"
else
echo "警告: 未安装 ImageMagick (convert),跳过图标生成。"
fi
fi
# 7. 创建 DEBIAN 控制文件
echo "7. 创建 DEBIAN 控制文件..."
cat > "$DEBIAN_DIR/control" << EOF
Package: $APP_NAME
Version: $APP_VERSION
Section: utils
Priority: optional
Architecture: $ARCHITECTURE
Depends: $DEPENDENCIES
Maintainer: $MAINTAINER
Description: $APP_DESCRIPTION
配置编辑器是一个功能强大的工具,用于编辑和管理各种配置文件。
支持以下功能:
* 智能解析配置文件
* 分组显示配置项
* 拖拽重新排序
* 加密配置项保护
* 会话超时锁定
* 用户认证系统
* 规则管理
* 在虚拟环境中运行,避免依赖冲突
Homepage: https://github.com/yourusername/config-editor
EOF
# 8. 创建安装后脚本(创建虚拟环境)
echo "8. 创建安装后脚本..."
cat > "$DEBIAN_DIR/postinst" << EOF
#!/bin/bash
# 安装后脚本 - 创建虚拟环境并安装依赖
set -e
# 更新桌面数据库
if [ -d /usr/share/applications ]; then
update-desktop-database /usr/share/applications || true
fi
# 更新图标缓存
if command -v gtk-update-icon-cache &> /dev/null; then
gtk-update-icon-cache -f -t /usr/share/icons/hicolor || true
fi
# 设置文件权限
chmod 755 $APP_INSTALL_PATH/*.py
chmod 755 $APP_INSTALL_PATH/login/*.py
chmod 755 /usr/bin/$APP_NAME
# 创建虚拟环境目录
echo "创建虚拟环境目录..."
mkdir -p "$VENV_PATH"
# 检查 Python3 是否可用
if ! command -v python3 &> /dev/null; then
echo "错误: Python3 未安装。请安装 python3。"
exit 1
fi
# 创建虚拟环境
echo "创建 Python 虚拟环境..."
python3 -m venv "$VENV_PATH" --system-site-packages
# 激活虚拟环境并安装依赖
echo "在虚拟环境中安装依赖..."
source "$VENV_PATH/bin/activate"
# 升级 pip
pip install --upgrade pip
# 安装依赖
if [ -f "$APP_INSTALL_PATH/requirements.txt" ]; then
echo "从 requirements.txt 安装依赖..."
pip install -r "$APP_INSTALL_PATH/requirements.txt"
else
echo "安装 PyQt6..."
pip install PyQt6
fi
# 验证安装
if python3 -c "import PyQt6; print('PyQt6 安装成功')" 2>/dev/null; then
echo "✅ 虚拟环境设置成功"
else
echo "❌ 虚拟环境设置失败,尝试重新安装 PyQt6..."
pip install --force-reinstall PyQt6
fi
# 确保规则文件可写
touch "$APP_INSTALL_PATH/config_editor_rules.json" 2>/dev/null || true
chmod 666 "$APP_INSTALL_PATH/config_editor_rules.json" 2>/dev/null || true
# 创建用户数据目录
mkdir -p "/var/lib/$APP_NAME"
chmod 755 "/var/lib/$APP_NAME"
echo "安装完成!您可以通过以下方式启动配置编辑器:"
echo "1. 在应用程序菜单中搜索 'Config Editor'"
echo "2. 在终端中运行: $APP_NAME"
echo "3. 首次运行需要设置配置文件路径"
echo ""
echo "虚拟环境位置: $VENV_PATH"
echo "应用程序位置: $APP_INSTALL_PATH"
EOF
chmod 755 "$DEBIAN_DIR/postinst"
# 9. 创建卸载前脚本
echo "9. 创建卸载前脚本..."
cat > "$DEBIAN_DIR/prerm" << EOF
#!/bin/bash
# 卸载前脚本
set -e
# 检查程序是否正在运行
if pgrep -f "$APP_NAME" > /dev/null; then
echo "正在停止运行中的配置编辑器..."
pkill -f "$APP_NAME" || true
sleep 2
fi
EOF
chmod 755 "$DEBIAN_DIR/prerm"
# 10. 创建卸载后脚本
echo "10. 创建卸载后脚本..."
cat > "$DEBIAN_DIR/postrm" << EOF
#!/bin/bash
# 卸载后脚本
set -e
# 更新桌面数据库
if [ -d /usr/share/applications ]; then
update-desktop-database /usr/share/applications || true
fi
# 更新图标缓存
if command -v gtk-update-icon-cache &> /dev/null; then
gtk-update-icon-cache -f -t /usr/share/icons/hicolor || true
fi
# 删除虚拟环境(如果存在)
if [ -d "$VENV_PATH" ]; then
echo "删除虚拟环境..."
rm -rf "$VENV_PATH"
fi
# 删除应用程序目录(如果存在)
if [ -d "$APP_INSTALL_PATH" ]; then
echo "删除应用程序目录..."
rm -rf "$APP_INSTALL_PATH"
fi
# 删除系统数据目录
if [ -d "/var/lib/$APP_NAME" ]; then
echo "删除系统数据目录..."
rm -rf "/var/lib/$APP_NAME"
fi
# 删除用户数据(可选)
echo "是否要删除用户数据n/yes"
echo "这包括:"
echo " - ~/.config_editor/ 目录"
echo " - ~/.config/config-editor/ 目录"
read -p "输入 'yes' 确认删除,其他跳过: " choice
if [ "\$choice" = "yes" ]; then
rm -rf ~/.config_editor 2>/dev/null || true
rm -rf ~/.config/config-editor 2>/dev/null || true
echo "用户数据已删除。"
else
echo "用户数据保留。"
fi
EOF
chmod 755 "$DEBIAN_DIR/postrm"
# 11. 创建版权文件
echo "11. 创建版权文件..."
cat > "$DEBIAN_DIR/copyright" << EOF
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: $APP_NAME
Source: https://github.com/yourusername/config-editor
Files: *
Copyright: $(date +%Y) Your Name
License: MIT
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
EOF
# 12. 设置文件权限
echo "12. 设置文件权限..."
find "$BUILD_ROOT" -type f -exec chmod 644 {} \;
find "$BUILD_ROOT" -type d -exec chmod 755 {} \;
chmod -R 755 "$DEBIAN_DIR"/* 2>/dev/null || true
chmod 755 "$BIN_DIR/$APP_NAME"
chmod 755 "$APP_DIR"/*.py 2>/dev/null || true
chmod 755 "$APP_DIR"/login/*.py 2>/dev/null || true
# 13. 创建虚拟环境占位符目录
echo "13. 创建虚拟环境占位符目录..."
mkdir -p "$BUILD_ROOT$VENV_PATH"
touch "$BUILD_ROOT$VENV_PATH/.placeholder"
echo "这是一个虚拟环境占位符,将在安装时创建实际的虚拟环境。" > "$BUILD_ROOT$VENV_PATH/README.txt"
# 14. 创建配置文件示例
echo "14. 创建配置文件示例..."
cat > "$VAR_LIB_DIR/config_example.py" << 'EOF'
"""配置文件示例"""
# 数据库配置
DATABASE_HOST = "localhost"
DATABASE_PORT = 3306
DATABASE_USER = "admin"
DATABASE_PASSWORD = "secret_password"
DATABASE_NAME = "myapp_db"
# 应用配置
APP_NAME = "My Application"
DEBUG_MODE = False
LOG_LEVEL = "INFO"
MAX_CONNECTIONS = 100
# API配置
API_KEY = "your_api_key_here"
API_TIMEOUT = 30
API_RETRIES = 3
# 服务配置
ENABLE_CACHE = True
CACHE_SIZE = 1024
ENABLE_SSL = True
# 邮件配置
SMTP_SERVER = "smtp.example.com"
SMTP_PORT = 587
EMAIL_FROM = "noreply@example.com"
# 安全配置
SESSION_TIMEOUT = 3600
PASSWORD_MIN_LENGTH = 8
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
# 第三方服务配置
STRIPE_API_KEY = "sk_test_1234567890"
AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
AWS_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
EOF
# 15. 创建虚拟环境初始化脚本
echo "15. 创建虚拟环境初始化脚本..."
cat > "$APP_DIR/init_venv.sh" << EOF
#!/bin/bash
# 虚拟环境初始化脚本
VENV_PATH="$VENV_PATH"
APP_DIR="$APP_INSTALL_PATH"
echo "初始化虚拟环境..."
echo "虚拟环境路径: \$VENV_PATH"
echo "应用路径: \$APP_DIR"
# 检查是否已存在虚拟环境
if [ -f "\$VENV_PATH/bin/activate" ]; then
echo "虚拟环境已存在,重新创建吗?(y/N)"
read -r response
if [[ ! \$response =~ ^[Yy]$ ]]; then
echo "操作取消。"
exit 0
fi
rm -rf "\$VENV_PATH"
fi
# 创建虚拟环境
echo "创建新的虚拟环境..."
python3 -m venv "\$VENV_PATH" --system-site-packages
# 激活虚拟环境
source "\$VENV_PATH/bin/activate"
# 升级pip
pip install --upgrade pip
# 安装依赖
if [ -f "\$APP_DIR/requirements.txt" ]; then
echo "安装依赖..."
pip install -r "\$APP_DIR/requirements.txt"
else
echo "安装 PyQt6..."
pip install PyQt6
fi
# 验证安装
if python3 -c "import PyQt6" &> /dev/null; then
echo "✅ 虚拟环境初始化成功!"
echo ""
echo "使用方法:"
echo "1. 激活虚拟环境: source \$VENV_PATH/bin/activate"
echo "2. 运行程序: cd \$APP_DIR && python main.py"
echo "3. 退出虚拟环境: deactivate"
else
echo "❌ 虚拟环境初始化失败!"
exit 1
fi
EOF
chmod +x "$APP_DIR/init_venv.sh"
# 16. 创建虚拟环境管理脚本
echo "16. 创建虚拟环境管理脚本..."
cat > "$APP_DIR/manage_venv.py" << 'EOF'
#!/usr/bin/env python3
"""
虚拟环境管理脚本
用于检查和维护配置编辑器的虚拟环境
"""
import os
import sys
import subprocess
import venv
VENV_PATH = "/opt/config-editor/venv"
APP_DIR = "/opt/config-editor"
def check_venv():
"""检查虚拟环境状态"""
print("检查虚拟环境状态...")
print(f"虚拟环境路径: {VENV_PATH}")
# 检查虚拟环境是否存在
if not os.path.exists(os.path.join(VENV_PATH, "bin", "activate")):
print("❌ 虚拟环境不存在")
return False
# 检查 Python 是否可用
venv_python = os.path.join(VENV_PATH, "bin", "python3")
if not os.path.exists(venv_python):
print("❌ 虚拟环境中的 Python 不存在")
return False
# 检查 PyQt6 是否已安装
try:
result = subprocess.run(
[venv_python, "-c", "import PyQt6; print('✅ PyQt6 已安装')"],
capture_output=True,
text=True
)
if result.returncode == 0:
print(result.stdout.strip())
return True
else:
print("❌ PyQt6 未安装或有问题")
print(f"错误信息: {result.stderr}")
return False
except Exception as e:
print(f"❌ 检查时出错: {e}")
return False
def recreate_venv():
"""重新创建虚拟环境"""
print("重新创建虚拟环境...")
# 删除现有虚拟环境
if os.path.exists(VENV_PATH):
print(f"删除现有虚拟环境: {VENV_PATH}")
subprocess.run(["rm", "-rf", VENV_PATH], check=False)
# 创建新虚拟环境
print("创建新虚拟环境...")
try:
venv.create(VENV_PATH, with_pip=True, system_site_packages=True)
except Exception as e:
print(f"❌ 创建虚拟环境失败: {e}")
return False
# 安装依赖
print("安装依赖...")
venv_pip = os.path.join(VENV_PATH, "bin", "pip3")
requirements_file = os.path.join(APP_DIR, "requirements.txt")
if os.path.exists(requirements_file):
print(f"从 {requirements_file} 安装依赖...")
result = subprocess.run([venv_pip, "install", "-r", requirements_file], capture_output=True, text=True)
else:
print("安装 PyQt6...")
result = subprocess.run([venv_pip, "install", "PyQt6"], capture_output=True, text=True)
if result.returncode != 0:
print(f"❌ 安装依赖失败: {result.stderr}")
return False
print("✅ 虚拟环境重新创建成功!")
return True
def show_venv_info():
"""显示虚拟环境信息"""
print("虚拟环境信息:")
print(f"路径: {VENV_PATH}")
if os.path.exists(os.path.join(VENV_PATH, "bin", "python3")):
venv_python = os.path.join(VENV_PATH, "bin", "python3")
result = subprocess.run([venv_python, "--version"], capture_output=True, text=True)
print(f"Python 版本: {result.stdout.strip()}")
result = subprocess.run([venv_python, "-m", "pip", "list"], capture_output=True, text=True)
print("\n已安装的包:")
print(result.stdout)
else:
print("❌ 虚拟环境不存在或已损坏")
def main():
"""主函数"""
print("配置编辑器虚拟环境管理工具")
print("=" * 40)
if len(sys.argv) < 2:
print("使用方法:")
print(" python manage_venv.py check - 检查虚拟环境状态")
print(" python manage_venv.py recreate - 重新创建虚拟环境")
print(" python manage_venv.py info - 显示虚拟环境信息")
return
command = sys.argv[1]
if command == "check":
if check_venv():
print("✅ 虚拟环境状态正常")
else:
print("❌ 虚拟环境有问题")
print("建议运行: python manage_venv.py recreate")
elif command == "recreate":
if recreate_venv():
print("✅ 虚拟环境重新创建成功")
else:
print("❌ 重新创建虚拟环境失败")
elif command == "info":
show_venv_info()
else:
print(f"未知命令: {command}")
if __name__ == "__main__":
main()
EOF
chmod +x "$APP_DIR/manage_venv.py"
# 17. 创建 README 文件
echo "17. 创建 README 文件..."
cat > "$APP_DIR/README.md" << EOF
# 配置编辑器 ($APP_NAME)
版本: $APP_VERSION
## 概述
配置编辑器是一个功能强大的工具,用于编辑和管理各种配置文件。
## 虚拟环境
此应用程序在独立的虚拟环境中运行,以避免与其他 Python 应用程序的依赖冲突。
虚拟环境位置: $VENV_PATH
## 使用方法
### 从菜单启动
1. 在应用程序菜单中搜索 "Config Editor"
2. 点击图标启动
### 从终端启动
\`\`\`bash
$APP_NAME
\`\`\`
### 手动激活虚拟环境
\`\`\`bash
source $VENV_PATH/bin/activate
cd $APP_INSTALL_PATH
python main.py
\`\`\`
## 管理虚拟环境
### 检查虚拟环境状态
\`\`\`bash
cd $APP_INSTALL_PATH
python manage_venv.py check
\`\`\`
### 重新创建虚拟环境
\`\`\`bash
cd $APP_INSTALL_PATH
python manage_venv.py recreate
\`\`\`
或使用脚本:
\`\`\`bash
cd $APP_INSTALL_PATH
./init_venv.sh
\`\`\`
### 查看虚拟环境信息
\`\`\`bash
cd $APP_INSTALL_PATH
python manage_venv.py info
\`\`\`
## 配置文件示例
配置文件示例位于: /var/lib/$APP_NAME/config_example.py
## 故障排除
### 1. 虚拟环境问题
如果应用程序无法启动,可能是虚拟环境有问题:
\`\`\`bash
cd $APP_INSTALL_PATH
./init_venv.sh
\`\`\`
### 2. 权限问题
如果无法保存设置,确保以下目录可写:
- $APP_INSTALL_PATH/config_editor_rules.json
- ~/.config_editor/
- ~/.config/config-editor/
### 3. 依赖问题
如果 PyQt6 有问题,重新安装:
\`\`\`bash
source $VENV_PATH/bin/activate
pip install --force-reinstall PyQt6
\`\`\`
## 支持
如有问题,请联系: $MAINTAINER
EOF
# 18. 计算安装大小
echo "18. 计算安装大小..."
INSTALLED_SIZE=$(du -sk "$BUILD_ROOT" | cut -f1)
sed -i "/^Architecture:/a Installed-Size: $INSTALLED_SIZE" "$DEBIAN_DIR/control"
# 19. 构建 deb 包
echo "19. 构建 deb 包..."
PACKAGE_NAME="${APP_NAME}_${APP_VERSION}_${ARCHITECTURE}.deb"
dpkg-deb --build "$BUILD_ROOT" "$PACKAGE_NAME"
# 20. 验证 deb 包
echo "20. 验证 deb 包..."
if [ -f "$PACKAGE_NAME" ]; then
echo "✅ 构建成功: $PACKAGE_NAME"
echo "文件大小: $(du -h "$PACKAGE_NAME" | cut -f1)"
# 显示包信息
echo -e "\n包内容:"
dpkg -c "$PACKAGE_NAME" | head -30
echo -e "\n包信息:"
dpkg -I "$PACKAGE_NAME"
# 清理构建目录
rm -rf "$BUILD_ROOT"
echo -e "\n========================================"
echo "✅ 构建完成!"
echo "生成的包: $PACKAGE_NAME"
echo "安装命令: sudo dpkg -i $PACKAGE_NAME"
echo "如果有依赖问题,运行: sudo apt-get install -f"
echo ""
echo "注意: 此版本使用虚拟环境"
echo "虚拟环境将在安装时自动创建"
echo "========================================"
else
echo "❌ 构建失败!"
exit 1
fi

179
config_parser.py Normal file
View File

@ -0,0 +1,179 @@
'''配置文件解析模块'''
import ast
import json
from typing import Dict, Tuple, List, Any
from models import ConfigField
from utils import get_field_type_from_value
class ConfigParser:
"""配置文件解析器"""
def __init__(self, rules: Dict):
self.rules = rules
def parse_config_file(self, config_file_path: str) -> Tuple[Dict, Dict[str, ConfigField], str]:
"""解析配置文件,精确匹配每个配置项的位置和注释"""
try:
with open(config_file_path, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
tree = ast.parse(content)
config_data = {}
all_config_fields = {}
# 第一遍:识别所有配置项及其位置
for node in ast.walk(tree):
if isinstance(node, ast.Assign):
for target in node.targets:
if isinstance(target, ast.Name) and target.id.isupper():
var_name = target.id
# 获取配置项在文件中的位置
assignment_line = node.lineno - 1 # ast行号从1开始我们使用0基索引
# 向上查找配置项上面的注释行
comment_lines = []
current_line = assignment_line - 1
while current_line >= 0:
line = lines[current_line].strip()
# 如果是注释行或空行,则包含在注释中
if line.startswith('#') or line == '':
comment_lines.insert(0, lines[current_line])
current_line -= 1
# 如果是多行注释的开始
elif line.startswith("'''") or line.startswith('"""'):
# 找到多行注释的起始位置
comment_start = current_line
while comment_start >= 0 and not (lines[comment_start].strip().endswith("'''") or lines[comment_start].strip().endswith('"""')):
comment_start -= 1
if comment_start >= 0:
for i in range(comment_start, current_line + 1):
comment_lines.insert(0, lines[i])
current_line = comment_start - 1
else:
break
else:
break
# 完整的配置项块(包括注释和赋值行)
full_block = comment_lines + [lines[assignment_line]]
# 如果赋值行有后续行(如多行字符串),添加它们
end_line = getattr(node, 'end_lineno', node.lineno) - 1
if end_line > assignment_line:
for i in range(assignment_line + 1, end_line + 1):
full_block.append(lines[i])
try:
# 获取配置项的值
var_value = eval(compile(ast.Expression(node.value), '<string>', 'eval'))
config_data[var_name] = var_value
# 创建ConfigField实例
config_field = self._create_config_field(
var_name, var_value, assignment_line,
full_block, comment_lines
)
all_config_fields[var_name] = config_field
except:
# 如果无法解析值,使用字符串表示
try:
value_str = ast.get_source_segment(content, node.value)
config_data[var_name] = value_str
config_field = self._create_config_field(
var_name, value_str, assignment_line,
full_block, comment_lines, is_string=True
)
all_config_fields[var_name] = config_field
except:
config_data[var_name] = "无法解析的值"
config_field = self._create_config_field(
var_name, "无法解析的值", assignment_line,
full_block, comment_lines, is_string=True
)
all_config_fields[var_name] = config_field
return config_data, all_config_fields, content
except Exception as e:
raise Exception(f"解析配置文件失败:{str(e)}")
def _create_config_field(self, var_name: str, var_value: Any, assignment_line: int,
full_block: List[str], comment_lines: List[str],
is_string: bool = False) -> ConfigField:
"""创建ConfigField实例"""
# 获取字段类型
field_type = self._get_field_type(var_name, var_value)
# 获取小数位数
decimals = self._get_field_decimals(var_name) if field_type == "float" else None
# 获取上次保存的值
last_saved_value = self._get_last_saved_value(var_name, var_value)
return ConfigField(
name=var_name,
value=var_value,
category=self._categorize_field(var_name),
display_name=self._get_display_name(var_name),
field_type=field_type,
decimals=decimals,
tooltip=self._get_tooltip(var_name),
hidden=self._is_hidden(var_name),
encrypted=self._is_encrypted(var_name), # 加密状态
line_number=assignment_line - len(comment_lines),
original_lines=full_block,
validation=self._get_validation(var_name),
last_saved_value=last_saved_value
)
def _categorize_field(self, field_name: str) -> str:
"""为字段分类"""
for category, fields in self.rules.get("categories", {}).items():
if field_name in fields:
return category
return "未分类"
def _get_display_name(self, field_name: str) -> str:
"""获取字段的显示名称"""
return self.rules.get("display_names", {}).get(field_name, field_name)
def _get_tooltip(self, field_name: str) -> str:
"""获取字段的提示信息"""
return self.rules.get("tooltips", {}).get(field_name, f"配置项: {field_name}")
def _get_field_type(self, field_name: str, value: Any) -> str:
"""获取字段类型"""
if field_name in self.rules.get("field_types", {}):
return self.rules["field_types"][field_name]
return get_field_type_from_value(value)
def _get_field_decimals(self, field_name: str) -> int:
"""获取字段的小数位数"""
return self.rules.get("field_decimals", {}).get(field_name, 6)
def _get_validation(self, field_name: str) -> Dict:
"""获取配置项的校验规则"""
return self.rules.get("validations", {}).get(field_name, {})
def _is_hidden(self, field_name: str) -> bool:
"""检查配置项是否被标记为隐藏"""
return field_name in self.rules.get("hidden", [])
def _is_encrypted(self, field_name: str) -> bool:
"""检查配置项是否被标记为加密"""
return field_name in self.rules.get("encrypted_fields", [])
def _get_last_saved_value(self, field_name: str, current_value: Any) -> Any:
"""获取配置项的上次保存值"""
last_saved_values = self.rules.get("last_saved_values", {})
if field_name in last_saved_values:
return last_saved_values[field_name]
return None

1036
dialogs.py Normal file

File diff suppressed because it is too large Load Diff

117
file_handler.py Normal file
View File

@ -0,0 +1,117 @@
'''文件读写管理模块'''
import os
import json
import shutil
from pathlib import Path
from typing import Dict, Any
from utils import (backup_existing_rules, merge_rules,
get_default_rules, ensure_rule_structure)
class FileHandler:
"""文件处理器"""
def __init__(self, program_dir: str):
self.program_dir = program_dir
self.rules_file = str(Path(program_dir) / "config_editor_rules.json")
self.settings_file = str(Path(program_dir) / "config_editor_settings.json")
def load_user_settings(self) -> Dict:
"""加载用户设置"""
try:
if os.path.exists(self.settings_file):
with open(self.settings_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"加载用户设置失败: {e}")
return {}
def save_user_settings(self, settings: Dict) -> bool:
"""保存用户设置"""
try:
with open(self.settings_file, 'w', encoding='utf-8') as f:
json.dump(settings, f, indent=2, ensure_ascii=False)
return True
except Exception as e:
print(f"保存用户设置失败: {e}")
return False
def load_rules(self) -> Dict:
"""加载规则文件"""
try:
# 先备份现有规则文件
backup_existing_rules(self.rules_file, self.program_dir)
# 检查是否已有规则文件
if os.path.exists(self.rules_file):
with open(self.rules_file, 'r', encoding='utf-8') as f:
existing_rules = json.load(f)
# 检查规则文件是否为空或格式错误
if not existing_rules or not isinstance(existing_rules, dict):
raise ValueError("规则文件为空或格式错误")
# 从打包资源加载默认规则(用于合并新字段)
default_rules = get_default_rules()
# 智能合并:保留现有规则,只添加新字段
rules = merge_rules(existing_rules, default_rules)
# 确保规则结构完整
rules = ensure_rule_structure(rules)
# 保存合并后的规则(包含新字段)
self.save_rules(rules)
return rules
else:
# 如果没有规则文件,使用默认规则
rules = get_default_rules()
# 确保规则结构完整
rules = ensure_rule_structure(rules)
# 首次运行,创建规则文件
try:
self.save_rules(rules)
except Exception as e:
print(f"创建规则文件失败: {e}")
return rules
except (json.JSONDecodeError, ValueError, KeyError) as e:
# 如果规则文件损坏,备份后使用默认规则
print(f"加载规则文件失败: {e},将使用默认规则")
self._backup_corrupted_rules()
rules = get_default_rules()
rules = ensure_rule_structure(rules)
self.save_rules(rules)
return rules
except Exception as e:
print(f"加载规则文件失败: {e}")
rules = get_default_rules()
rules = ensure_rule_structure(rules)
return rules
def save_rules(self, rules: Dict) -> bool:
"""保存规则文件"""
try:
# 确保规则结构完整
rules = ensure_rule_structure(rules)
with open(self.rules_file, 'w', encoding='utf-8') as f:
json.dump(rules, f, indent=2, ensure_ascii=False)
return True
except Exception as e:
print(f"保存规则文件失败: {e}")
return False
def _backup_corrupted_rules(self):
"""备份损坏的规则文件"""
if os.path.exists(self.rules_file):
import datetime
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = f"{self.rules_file}.corrupted_{timestamp}.bak"
try:
shutil.copy2(self.rules_file, backup_file)
print(f"已备份损坏的规则文件到: {backup_file}")
except Exception as e:
print(f"备份损坏规则文件失败: {e}")