上传文件至 /
This commit is contained in:
parent
e51b895bc8
commit
93309fb762
10
__init__.py
Normal file
10
__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""
|
||||
配置编辑器模块
|
||||
"""
|
||||
|
||||
__version__ = "1.3"
|
||||
__author__ = "Config Editor"
|
||||
|
||||
from main_window import ConfigEditor
|
||||
|
||||
__all__ = ['ConfigEditor']
|
||||
724
build.sh
Normal file
724
build.sh
Normal 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
179
config_parser.py
Normal 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
1036
dialogs.py
Normal file
File diff suppressed because it is too large
Load Diff
117
file_handler.py
Normal file
117
file_handler.py
Normal 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}")
|
||||
Loading…
x
Reference in New Issue
Block a user