|
@@ -1,14 +1,18 @@
|
|
import sys
|
|
import sys
|
|
import os
|
|
import os
|
|
|
|
+import threading
|
|
|
|
+import subprocess
|
|
from PyQt5.QtWidgets import (
|
|
from PyQt5.QtWidgets import (
|
|
QApplication, QTabWidget, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QApplication, QTabWidget, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QRadioButton, QPushButton, QButtonGroup, QGroupBox, QMessageBox,
|
|
QRadioButton, QPushButton, QButtonGroup, QGroupBox, QMessageBox,
|
|
- QLineEdit, QScrollArea, QFileDialog, QFormLayout, QCheckBox
|
|
|
|
|
|
+ QLineEdit, QScrollArea, QFileDialog, QFormLayout, QCheckBox, QTextEdit,
|
|
|
|
+ QComboBox, QDialog, QDialogButtonBox, QGridLayout, QToolButton
|
|
)
|
|
)
|
|
-from PyQt5.QtCore import Qt
|
|
|
|
|
|
+from PyQt5.QtCore import Qt, pyqtSignal, QObject
|
|
from repo_sync import RepoSync, __version__
|
|
from repo_sync import RepoSync, __version__
|
|
-from dotenv import load_dotenv, set_key, find_dotenv
|
|
|
|
|
|
+from dotenv import load_dotenv, set_key, find_dotenv, dotenv_values
|
|
import json
|
|
import json
|
|
|
|
+import uuid
|
|
|
|
|
|
# Explorer路径获取
|
|
# Explorer路径获取
|
|
try:
|
|
try:
|
|
@@ -23,6 +27,11 @@ except ImportError:
|
|
def get_active_explorer_path():
|
|
def get_active_explorer_path():
|
|
return os.getcwd()
|
|
return os.getcwd()
|
|
|
|
|
|
|
|
+# 命令执行信号类
|
|
|
|
+class CommandSignals(QObject):
|
|
|
|
+ output = pyqtSignal(str)
|
|
|
|
+ finished = pyqtSignal(int)
|
|
|
|
+
|
|
class MainTab(QWidget):
|
|
class MainTab(QWidget):
|
|
def __init__(self, parent=None):
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
super().__init__(parent)
|
|
@@ -67,17 +76,80 @@ class MainTab(QWidget):
|
|
pf_group.setLayout(pf_layout)
|
|
pf_group.setLayout(pf_layout)
|
|
layout.addWidget(pf_group)
|
|
layout.addWidget(pf_group)
|
|
|
|
|
|
- # run按钮
|
|
|
|
|
|
+ # 账户选择
|
|
|
|
+ account_layout = QHBoxLayout()
|
|
|
|
+ account_layout.addWidget(QLabel("Account:"))
|
|
|
|
+ self.account_combo = QComboBox()
|
|
|
|
+ self.account_combo.setMinimumWidth(200)
|
|
|
|
+ account_layout.addWidget(self.account_combo)
|
|
|
|
+ account_layout.addStretch()
|
|
|
|
+ layout.addLayout(account_layout)
|
|
|
|
+
|
|
|
|
+ # 按钮区域 (run和cancel)
|
|
|
|
+ btn_layout = QHBoxLayout()
|
|
self.run_btn = QPushButton("run it")
|
|
self.run_btn = QPushButton("run it")
|
|
self.run_btn.clicked.connect(self.run_repo_sync)
|
|
self.run_btn.clicked.connect(self.run_repo_sync)
|
|
- layout.addWidget(self.run_btn, alignment=Qt.AlignCenter)
|
|
|
|
|
|
+ self.cancel_btn = QPushButton("Cancel")
|
|
|
|
+ self.cancel_btn.clicked.connect(self.cancel_operation)
|
|
|
|
+ self.cancel_btn.setEnabled(False)
|
|
|
|
+ btn_layout.addWidget(self.run_btn)
|
|
|
|
+ btn_layout.addWidget(self.cancel_btn)
|
|
|
|
+ layout.addLayout(btn_layout)
|
|
|
|
+
|
|
|
|
+ # 命令执行结果
|
|
|
|
+ result_group = QGroupBox("Execution Result:")
|
|
|
|
+ result_layout = QVBoxLayout()
|
|
|
|
+ self.result_text = QTextEdit()
|
|
|
|
+ self.result_text.setReadOnly(True)
|
|
|
|
+ result_layout.addWidget(self.result_text)
|
|
|
|
+ result_group.setLayout(result_layout)
|
|
|
|
+ layout.addWidget(result_group)
|
|
|
|
+
|
|
self.setLayout(layout)
|
|
self.setLayout(layout)
|
|
|
|
+
|
|
|
|
+ # 命令执行相关
|
|
|
|
+ self.process = None
|
|
|
|
+ self.command_signals = CommandSignals()
|
|
|
|
+ self.command_signals.output.connect(self.update_output)
|
|
|
|
+ self.command_signals.finished.connect(self.process_finished)
|
|
|
|
+
|
|
|
|
+ # 平台变更时更新账户列表
|
|
|
|
+ self.pf_buttons.buttonClicked.connect(self.update_account_list)
|
|
|
|
+ self.update_account_list()
|
|
|
|
|
|
def choose_path(self):
|
|
def choose_path(self):
|
|
path = QFileDialog.getExistingDirectory(self, "Select Directory")
|
|
path = QFileDialog.getExistingDirectory(self, "Select Directory")
|
|
if path:
|
|
if path:
|
|
self.path_edit.setText(path)
|
|
self.path_edit.setText(path)
|
|
|
|
|
|
|
|
+ def update_account_list(self):
|
|
|
|
+ self.account_combo.clear()
|
|
|
|
+ pf_id = self.pf_buttons.checkedId()
|
|
|
|
+ platform = self.platforms[pf_id]
|
|
|
|
+
|
|
|
|
+ # 读取所有账户
|
|
|
|
+ accounts = self.get_platform_accounts(platform)
|
|
|
|
+ for account_name in accounts:
|
|
|
|
+ self.account_combo.addItem(account_name)
|
|
|
|
+
|
|
|
|
+ def get_platform_accounts(self, platform):
|
|
|
|
+ # 读取.env文件中的所有配置
|
|
|
|
+ env_values = dotenv_values(find_dotenv())
|
|
|
|
+ accounts = set()
|
|
|
|
+
|
|
|
|
+ # 默认账户
|
|
|
|
+ accounts.add("default")
|
|
|
|
+
|
|
|
|
+ # 查找带有账户名的配置
|
|
|
|
+ prefix = f"{platform}_"
|
|
|
|
+ for key in env_values.keys():
|
|
|
|
+ if key.startswith(prefix) and "_" in key[len(prefix):]:
|
|
|
|
+ account_name = key[len(prefix):].split("_")[0]
|
|
|
|
+ if account_name != "default":
|
|
|
|
+ accounts.add(account_name)
|
|
|
|
+
|
|
|
|
+ return sorted(list(accounts))
|
|
|
|
+
|
|
def run_repo_sync(self):
|
|
def run_repo_sync(self):
|
|
repo_path = self.path_edit.text().strip()
|
|
repo_path = self.path_edit.text().strip()
|
|
if not repo_path:
|
|
if not repo_path:
|
|
@@ -88,28 +160,139 @@ class MainTab(QWidget):
|
|
pf_id = self.pf_buttons.checkedId()
|
|
pf_id = self.pf_buttons.checkedId()
|
|
op = ["create", "push", "pull", "clone", "delete"][op_id]
|
|
op = ["create", "push", "pull", "clone", "delete"][op_id]
|
|
pf = self.platforms[pf_id]
|
|
pf = self.platforms[pf_id]
|
|
|
|
+ account = self.account_combo.currentText()
|
|
|
|
+
|
|
|
|
+ # 清空结果区域
|
|
|
|
+ self.result_text.clear()
|
|
|
|
|
|
# 检查平台配置
|
|
# 检查平台配置
|
|
load_dotenv()
|
|
load_dotenv()
|
|
- if not os.getenv(f"{pf}_token"):
|
|
|
|
- QMessageBox.warning(self, "Warning", f"Please configure {pf} token in Settings tab first.")
|
|
|
|
|
|
+ token_key = f"{pf}_{account}_token" if account != "default" else f"{pf}_token"
|
|
|
|
+ if not os.getenv(token_key):
|
|
|
|
+ QMessageBox.warning(self, "Warning", f"Please configure {pf} token for account '{account}' in Settings tab first.")
|
|
return
|
|
return
|
|
|
|
|
|
- params = {
|
|
|
|
- "command": op,
|
|
|
|
- "platform": pf,
|
|
|
|
- "repo_path": repo_path,
|
|
|
|
- f"{pf}_token": os.getenv(f"{pf}_token"),
|
|
|
|
- f"{pf}_username": os.getenv(f"{pf}_username"),
|
|
|
|
- f"{pf}_private": os.getenv(f"{pf}_private", "true")
|
|
|
|
- }
|
|
|
|
|
|
+ # 构建命令
|
|
|
|
+ cmd = [sys.executable, "-m", "repo_sync"]
|
|
|
|
+ cmd.append(op)
|
|
|
|
+ cmd.extend(["-p", pf])
|
|
|
|
+ cmd.extend(["-repo_path", repo_path])
|
|
|
|
+
|
|
|
|
+ # 执行命令
|
|
|
|
+ self.run_btn.setEnabled(False)
|
|
|
|
+ self.cancel_btn.setEnabled(True)
|
|
|
|
+ self.result_text.append(f"Running: {' '.join(cmd)}\n")
|
|
|
|
|
|
|
|
+ # 在新线程中执行命令
|
|
|
|
+ self.process_thread = threading.Thread(
|
|
|
|
+ target=self.run_process,
|
|
|
|
+ args=(cmd,)
|
|
|
|
+ )
|
|
|
|
+ self.process_thread.daemon = True
|
|
|
|
+ self.process_thread.start()
|
|
|
|
+
|
|
|
|
+ def run_process(self, cmd):
|
|
try:
|
|
try:
|
|
- rs = RepoSync(params)
|
|
|
|
- rs.run()
|
|
|
|
- QMessageBox.information(self, "Success", f"Operation '{op}' on '{pf}' finished.")
|
|
|
|
|
|
+ self.process = subprocess.Popen(
|
|
|
|
+ cmd,
|
|
|
|
+ stdout=subprocess.PIPE,
|
|
|
|
+ stderr=subprocess.STDOUT,
|
|
|
|
+ text=True,
|
|
|
|
+ bufsize=1,
|
|
|
|
+ universal_newlines=True
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 读取输出
|
|
|
|
+ for line in self.process.stdout:
|
|
|
|
+ self.command_signals.output.emit(line)
|
|
|
|
+
|
|
|
|
+ self.process.wait()
|
|
|
|
+ self.command_signals.finished.emit(self.process.returncode)
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- QMessageBox.critical(self, "Error", str(e))
|
|
|
|
|
|
+ self.command_signals.output.emit(f"Error: {str(e)}")
|
|
|
|
+ self.command_signals.finished.emit(1)
|
|
|
|
+
|
|
|
|
+ def update_output(self, text):
|
|
|
|
+ self.result_text.append(text)
|
|
|
|
+ # 自动滚动到底部
|
|
|
|
+ self.result_text.verticalScrollBar().setValue(
|
|
|
|
+ self.result_text.verticalScrollBar().maximum()
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ def process_finished(self, return_code):
|
|
|
|
+ self.process = None
|
|
|
|
+ self.run_btn.setEnabled(True)
|
|
|
|
+ self.cancel_btn.setEnabled(False)
|
|
|
|
+
|
|
|
|
+ if return_code == 0:
|
|
|
|
+ self.result_text.append("\nOperation completed successfully.")
|
|
|
|
+ else:
|
|
|
|
+ self.result_text.append(f"\nOperation failed with return code {return_code}.")
|
|
|
|
+
|
|
|
|
+ def cancel_operation(self):
|
|
|
|
+ if self.process:
|
|
|
|
+ self.process.terminate()
|
|
|
|
+ self.result_text.append("\nOperation cancelled by user.")
|
|
|
|
+
|
|
|
|
+# 添加账户对话框
|
|
|
|
+class AddAccountDialog(QDialog):
|
|
|
|
+ def __init__(self, platform, parent=None):
|
|
|
|
+ super().__init__(parent)
|
|
|
|
+ self.platform = platform
|
|
|
|
+ self.setWindowTitle(f"Add {platform.capitalize()} Account")
|
|
|
|
+ self.resize(400, 200)
|
|
|
|
+
|
|
|
|
+ layout = QVBoxLayout()
|
|
|
|
+
|
|
|
|
+ form_layout = QFormLayout()
|
|
|
|
+ self.account_name = QLineEdit()
|
|
|
|
+ form_layout.addRow("Account Name:", self.account_name)
|
|
|
|
+
|
|
|
|
+ # 根据平台添加相应字段
|
|
|
|
+ self.fields = {}
|
|
|
|
+ platform_fields = {
|
|
|
|
+ "github": ["username", "token", "private"],
|
|
|
|
+ "gitlab": ["host", "username", "token", "private"],
|
|
|
|
+ "gitee": ["username", "token", "private"],
|
|
|
|
+ "gitcode": ["username", "token", "private"],
|
|
|
|
+ "git.yoq.me": ["username", "token", "private"],
|
|
|
|
+ "coding": ["username", "token", "project", "private"],
|
|
|
|
+ "aliyun": ["compoanyid", "group_id", "username", "token", "private"],
|
|
|
|
+ "cnb": ["username", "token", "private"]
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for field in platform_fields.get(platform, ["username", "token"]):
|
|
|
|
+ if field == "private":
|
|
|
|
+ widget = QCheckBox()
|
|
|
|
+ widget.setChecked(True)
|
|
|
|
+ else:
|
|
|
|
+ widget = QLineEdit()
|
|
|
|
+ if field in ["token", "password"]:
|
|
|
|
+ widget.setEchoMode(QLineEdit.Password)
|
|
|
|
+
|
|
|
|
+ self.fields[field] = widget
|
|
|
|
+ form_layout.addRow(f"{field.capitalize()}:", widget)
|
|
|
|
+
|
|
|
|
+ layout.addLayout(form_layout)
|
|
|
|
+
|
|
|
|
+ # 按钮
|
|
|
|
+ buttons = QDialogButtonBox(
|
|
|
|
+ QDialogButtonBox.Ok | QDialogButtonBox.Cancel
|
|
|
|
+ )
|
|
|
|
+ buttons.accepted.connect(self.accept)
|
|
|
|
+ buttons.rejected.connect(self.reject)
|
|
|
|
+ layout.addWidget(buttons)
|
|
|
|
+
|
|
|
|
+ self.setLayout(layout)
|
|
|
|
+
|
|
|
|
+ def get_account_data(self):
|
|
|
|
+ data = {"name": self.account_name.text()}
|
|
|
|
+ for field, widget in self.fields.items():
|
|
|
|
+ if isinstance(widget, QCheckBox):
|
|
|
|
+ data[field] = widget.isChecked()
|
|
|
|
+ else:
|
|
|
|
+ data[field] = widget.text()
|
|
|
|
+ return data
|
|
|
|
|
|
class SettingsTab(QWidget):
|
|
class SettingsTab(QWidget):
|
|
def __init__(self, parent=None):
|
|
def __init__(self, parent=None):
|
|
@@ -124,7 +307,7 @@ class SettingsTab(QWidget):
|
|
scroll = QScrollArea()
|
|
scroll = QScrollArea()
|
|
scroll.setWidgetResizable(True)
|
|
scroll.setWidgetResizable(True)
|
|
content = QWidget()
|
|
content = QWidget()
|
|
- self.form_layout = QFormLayout()
|
|
|
|
|
|
+ content_layout = QVBoxLayout()
|
|
|
|
|
|
# 平台配置
|
|
# 平台配置
|
|
self.platform_configs = {
|
|
self.platform_configs = {
|
|
@@ -138,61 +321,258 @@ class SettingsTab(QWidget):
|
|
"cnb": ["username", "token", "private"]
|
|
"cnb": ["username", "token", "private"]
|
|
}
|
|
}
|
|
|
|
|
|
- self.config_widgets = {}
|
|
|
|
- for platform, fields in self.platform_configs.items():
|
|
|
|
|
|
+ # 为每个平台创建分组
|
|
|
|
+ self.platform_groups = {}
|
|
|
|
+ for platform in self.platform_configs.keys():
|
|
group = QGroupBox(platform.capitalize())
|
|
group = QGroupBox(platform.capitalize())
|
|
- group_layout = QFormLayout()
|
|
|
|
-
|
|
|
|
- platform_widgets = {}
|
|
|
|
- for field in fields:
|
|
|
|
- if field == "private":
|
|
|
|
- widget = QCheckBox()
|
|
|
|
- widget.setChecked(True)
|
|
|
|
- else:
|
|
|
|
- widget = QLineEdit()
|
|
|
|
- if field in ["token", "password"]:
|
|
|
|
- widget.setEchoMode(QLineEdit.Password)
|
|
|
|
-
|
|
|
|
- field_name = f"{platform}_{field}"
|
|
|
|
- platform_widgets[field_name] = widget
|
|
|
|
- group_layout.addRow(f"{field.capitalize()}:", widget)
|
|
|
|
|
|
+ group_layout = QVBoxLayout()
|
|
|
|
+
|
|
|
|
+ # 账户选择和管理
|
|
|
|
+ account_header = QHBoxLayout()
|
|
|
|
+ account_header.addWidget(QLabel("Accounts:"))
|
|
|
|
+ account_combo = QComboBox()
|
|
|
|
+ account_combo.setMinimumWidth(200)
|
|
|
|
+ account_header.addWidget(account_combo)
|
|
|
|
+
|
|
|
|
+ # 添加账户按钮
|
|
|
|
+ add_btn = QToolButton()
|
|
|
|
+ add_btn.setText("+")
|
|
|
|
+ add_btn.clicked.connect(lambda checked, p=platform: self.add_account(p))
|
|
|
|
+ account_header.addWidget(add_btn)
|
|
|
|
+
|
|
|
|
+ # 删除账户按钮
|
|
|
|
+ del_btn = QToolButton()
|
|
|
|
+ del_btn.setText("-")
|
|
|
|
+ del_btn.clicked.connect(lambda checked, p=platform, c=account_combo: self.delete_account(p, c))
|
|
|
|
+ account_header.addWidget(del_btn)
|
|
|
|
+
|
|
|
|
+ # 启用账户按钮
|
|
|
|
+ enable_btn = QPushButton("Enable")
|
|
|
|
+ enable_btn.clicked.connect(lambda checked, p=platform, c=account_combo: self.enable_account(p, c))
|
|
|
|
+ account_header.addWidget(enable_btn)
|
|
|
|
+
|
|
|
|
+ group_layout.addLayout(account_header)
|
|
|
|
+
|
|
|
|
+ # 账户详情区域
|
|
|
|
+ account_details = QWidget()
|
|
|
|
+ account_form = QFormLayout()
|
|
|
|
+ account_details.setLayout(account_form)
|
|
|
|
+ group_layout.addWidget(account_details)
|
|
|
|
|
|
- self.config_widgets.update(platform_widgets)
|
|
|
|
group.setLayout(group_layout)
|
|
group.setLayout(group_layout)
|
|
- self.form_layout.addRow(group)
|
|
|
|
|
|
+ content_layout.addWidget(group)
|
|
|
|
+
|
|
|
|
+ # 保存引用
|
|
|
|
+ self.platform_groups[platform] = {
|
|
|
|
+ "group": group,
|
|
|
|
+ "combo": account_combo,
|
|
|
|
+ "details": account_details,
|
|
|
|
+ "form": account_form
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ content.setLayout(content_layout)
|
|
|
|
+ scroll.setWidget(content)
|
|
|
|
+ layout.addWidget(scroll)
|
|
|
|
|
|
# 保存按钮
|
|
# 保存按钮
|
|
self.save_btn = QPushButton("Save Settings")
|
|
self.save_btn = QPushButton("Save Settings")
|
|
self.save_btn.clicked.connect(self.save_settings)
|
|
self.save_btn.clicked.connect(self.save_settings)
|
|
-
|
|
|
|
- content.setLayout(self.form_layout)
|
|
|
|
- scroll.setWidget(content)
|
|
|
|
- layout.addWidget(scroll)
|
|
|
|
layout.addWidget(self.save_btn, alignment=Qt.AlignCenter)
|
|
layout.addWidget(self.save_btn, alignment=Qt.AlignCenter)
|
|
|
|
+
|
|
self.setLayout(layout)
|
|
self.setLayout(layout)
|
|
|
|
|
|
def load_settings(self):
|
|
def load_settings(self):
|
|
- load_dotenv()
|
|
|
|
- for field_name, widget in self.config_widgets.items():
|
|
|
|
- value = os.getenv(field_name)
|
|
|
|
- if isinstance(widget, QCheckBox):
|
|
|
|
- widget.setChecked(value != "false")
|
|
|
|
- elif value:
|
|
|
|
|
|
+ # 读取.env文件
|
|
|
|
+ env_values = dotenv_values(find_dotenv())
|
|
|
|
+
|
|
|
|
+ # 为每个平台加载账户
|
|
|
|
+ for platform, group_data in self.platform_groups.items():
|
|
|
|
+ combo = group_data["combo"]
|
|
|
|
+ combo.clear()
|
|
|
|
+
|
|
|
|
+ # 查找该平台的所有账户
|
|
|
|
+ accounts = self.get_platform_accounts(platform, env_values)
|
|
|
|
+
|
|
|
|
+ # 添加到下拉框
|
|
|
|
+ for account in accounts:
|
|
|
|
+ combo.addItem(account)
|
|
|
|
+
|
|
|
|
+ # 连接选择变更事件
|
|
|
|
+ combo.currentIndexChanged.connect(
|
|
|
|
+ lambda idx, p=platform: self.update_account_details(p)
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 更新当前选择的账户详情
|
|
|
|
+ if combo.count() > 0:
|
|
|
|
+ self.update_account_details(platform)
|
|
|
|
+
|
|
|
|
+ def get_platform_accounts(self, platform, env_values=None):
|
|
|
|
+ if env_values is None:
|
|
|
|
+ env_values = dotenv_values(find_dotenv())
|
|
|
|
+
|
|
|
|
+ accounts = set()
|
|
|
|
+ # 默认账户
|
|
|
|
+ accounts.add("default")
|
|
|
|
+
|
|
|
|
+ # 查找带有账户名的配置
|
|
|
|
+ prefix = f"{platform}_"
|
|
|
|
+ for key in env_values.keys():
|
|
|
|
+ if key.startswith(prefix) and "_" in key[len(prefix):]:
|
|
|
|
+ account_name = key[len(prefix):].split("_")[0]
|
|
|
|
+ if account_name != "default":
|
|
|
|
+ accounts.add(account_name)
|
|
|
|
+
|
|
|
|
+ return sorted(list(accounts))
|
|
|
|
+
|
|
|
|
+ def update_account_details(self, platform):
|
|
|
|
+ group_data = self.platform_groups[platform]
|
|
|
|
+ combo = group_data["combo"]
|
|
|
|
+ form = group_data["form"]
|
|
|
|
+
|
|
|
|
+ # 清空表单
|
|
|
|
+ while form.rowCount() > 0:
|
|
|
|
+ form.removeRow(0)
|
|
|
|
+
|
|
|
|
+ # 获取当前选择的账户
|
|
|
|
+ account = combo.currentText()
|
|
|
|
+ if not account:
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # 读取账户配置
|
|
|
|
+ env_values = dotenv_values(find_dotenv())
|
|
|
|
+
|
|
|
|
+ # 创建表单项
|
|
|
|
+ self.field_widgets = {}
|
|
|
|
+ for field in self.platform_configs[platform]:
|
|
|
|
+ key = f"{platform}_{account}_{field}" if account != "default" else f"{platform}_{field}"
|
|
|
|
+ value = env_values.get(key, "")
|
|
|
|
+
|
|
|
|
+ if field == "private":
|
|
|
|
+ widget = QCheckBox()
|
|
|
|
+ widget.setChecked(value.lower() != "false")
|
|
|
|
+ else:
|
|
|
|
+ widget = QLineEdit()
|
|
|
|
+ if field in ["token", "password"]:
|
|
|
|
+ widget.setEchoMode(QLineEdit.Password)
|
|
widget.setText(value)
|
|
widget.setText(value)
|
|
|
|
+
|
|
|
|
+ self.field_widgets[key] = widget
|
|
|
|
+ form.addRow(f"{field.capitalize()}:", widget)
|
|
|
|
+
|
|
|
|
+ def add_account(self, platform):
|
|
|
|
+ dialog = AddAccountDialog(platform, self)
|
|
|
|
+ if dialog.exec_() == QDialog.Accepted:
|
|
|
|
+ account_data = dialog.get_account_data()
|
|
|
|
+ account_name = account_data["name"]
|
|
|
|
+
|
|
|
|
+ if not account_name:
|
|
|
|
+ QMessageBox.warning(self, "Warning", "Account name cannot be empty.")
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # 更新.env文件
|
|
|
|
+ env_file = find_dotenv()
|
|
|
|
+ if not env_file:
|
|
|
|
+ env_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env')
|
|
|
|
+
|
|
|
|
+ for field, value in account_data.items():
|
|
|
|
+ if field == "name":
|
|
|
|
+ continue
|
|
|
|
+
|
|
|
|
+ key = f"{platform}_{account_name}_{field}"
|
|
|
|
+ if isinstance(value, bool):
|
|
|
|
+ value = str(value).lower()
|
|
|
|
+
|
|
|
|
+ set_key(env_file, key, value)
|
|
|
|
+
|
|
|
|
+ # 重新加载设置
|
|
|
|
+ self.load_settings()
|
|
|
|
+
|
|
|
|
+ # 选择新账户
|
|
|
|
+ combo = self.platform_groups[platform]["combo"]
|
|
|
|
+ idx = combo.findText(account_name)
|
|
|
|
+ if idx >= 0:
|
|
|
|
+ combo.setCurrentIndex(idx)
|
|
|
|
+
|
|
|
|
+ def delete_account(self, platform, combo):
|
|
|
|
+ account = combo.currentText()
|
|
|
|
+ if account == "default":
|
|
|
|
+ QMessageBox.warning(self, "Warning", "Cannot delete the default account.")
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ reply = QMessageBox.question(
|
|
|
|
+ self,
|
|
|
|
+ "Confirm Deletion",
|
|
|
|
+ f"Are you sure you want to delete the account '{account}' for {platform}?",
|
|
|
|
+ QMessageBox.Yes | QMessageBox.No,
|
|
|
|
+ QMessageBox.No
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ if reply == QMessageBox.Yes:
|
|
|
|
+ # 删除.env中的相关配置
|
|
|
|
+ env_file = find_dotenv()
|
|
|
|
+ env_values = dotenv_values(env_file)
|
|
|
|
+
|
|
|
|
+ prefix = f"{platform}_{account}_"
|
|
|
|
+ keys_to_remove = [k for k in env_values.keys() if k.startswith(prefix)]
|
|
|
|
+
|
|
|
|
+ # 重写.env文件,排除要删除的键
|
|
|
|
+ with open(env_file, 'w') as f:
|
|
|
|
+ for k, v in env_values.items():
|
|
|
|
+ if k not in keys_to_remove:
|
|
|
|
+ f.write(f"{k}={v}\n")
|
|
|
|
+
|
|
|
|
+ # 重新加载设置
|
|
|
|
+ self.load_settings()
|
|
|
|
+
|
|
|
|
+ def enable_account(self, platform, combo):
|
|
|
|
+ account = combo.currentText()
|
|
|
|
+ if account == "default":
|
|
|
|
+ QMessageBox.information(self, "Information", "Default account is already enabled.")
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # 读取账户配置
|
|
|
|
+ env_file = find_dotenv()
|
|
|
|
+ env_values = dotenv_values(env_file)
|
|
|
|
+
|
|
|
|
+ # 获取账户配置
|
|
|
|
+ account_config = {}
|
|
|
|
+ prefix = f"{platform}_{account}_"
|
|
|
|
+ for key, value in env_values.items():
|
|
|
|
+ if key.startswith(prefix):
|
|
|
|
+ field = key[len(prefix):]
|
|
|
|
+ account_config[field] = value
|
|
|
|
+
|
|
|
|
+ # 更新默认配置
|
|
|
|
+ for field, value in account_config.items():
|
|
|
|
+ default_key = f"{platform}_{field}"
|
|
|
|
+ set_key(env_file, default_key, value)
|
|
|
|
+
|
|
|
|
+ QMessageBox.information(
|
|
|
|
+ self,
|
|
|
|
+ "Success",
|
|
|
|
+ f"Account '{account}' has been enabled as the default for {platform}."
|
|
|
|
+ )
|
|
|
|
|
|
def save_settings(self):
|
|
def save_settings(self):
|
|
env_file = find_dotenv()
|
|
env_file = find_dotenv()
|
|
if not env_file:
|
|
if not env_file:
|
|
env_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env')
|
|
env_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env')
|
|
|
|
|
|
- for field_name, widget in self.config_widgets.items():
|
|
|
|
- if isinstance(widget, QCheckBox):
|
|
|
|
- value = str(widget.isChecked()).lower()
|
|
|
|
- else:
|
|
|
|
- value = widget.text().strip()
|
|
|
|
|
|
+ # 保存当前显示的账户配置
|
|
|
|
+ for platform, group_data in self.platform_groups.items():
|
|
|
|
+ combo = group_data["combo"]
|
|
|
|
+ account = combo.currentText()
|
|
|
|
|
|
- if value:
|
|
|
|
- set_key(env_file, field_name, value)
|
|
|
|
|
|
+ if account and hasattr(self, 'field_widgets'):
|
|
|
|
+ for key, widget in self.field_widgets.items():
|
|
|
|
+ if key.startswith(f"{platform}_{account}"):
|
|
|
|
+ if isinstance(widget, QCheckBox):
|
|
|
|
+ value = str(widget.isChecked()).lower()
|
|
|
|
+ else:
|
|
|
|
+ value = widget.text().strip()
|
|
|
|
+
|
|
|
|
+ if value:
|
|
|
|
+ set_key(env_file, key, value)
|
|
|
|
|
|
QMessageBox.information(self, "Success", "Settings saved successfully!")
|
|
QMessageBox.information(self, "Success", "Settings saved successfully!")
|
|
|
|
|
|
@@ -208,13 +588,15 @@ class AboutTab(QWidget):
|
|
layout.addWidget(QLabel("- 支持创建/推送/拉取/克隆/删除操作"))
|
|
layout.addWidget(QLabel("- 支持创建/推送/拉取/克隆/删除操作"))
|
|
layout.addWidget(QLabel("- 自动获取资源管理器当前路径"))
|
|
layout.addWidget(QLabel("- 自动获取资源管理器当前路径"))
|
|
layout.addWidget(QLabel("- 配置信息保存在.env文件中"))
|
|
layout.addWidget(QLabel("- 配置信息保存在.env文件中"))
|
|
|
|
+ layout.addWidget(QLabel("- 支持每个平台配置多个账户"))
|
|
|
|
+ layout.addWidget(QLabel("- 命令行执行结果实时显示"))
|
|
self.setLayout(layout)
|
|
self.setLayout(layout)
|
|
|
|
|
|
class RepoSyncMainWindow(QTabWidget):
|
|
class RepoSyncMainWindow(QTabWidget):
|
|
def __init__(self):
|
|
def __init__(self):
|
|
super().__init__()
|
|
super().__init__()
|
|
self.setWindowTitle('repo_sync tools v1.12')
|
|
self.setWindowTitle('repo_sync tools v1.12')
|
|
- self.resize(800, 600)
|
|
|
|
|
|
+ self.resize(800, 700)
|
|
self.main_tab = MainTab()
|
|
self.main_tab = MainTab()
|
|
self.addTab(self.main_tab, '主界面')
|
|
self.addTab(self.main_tab, '主界面')
|
|
self.settings_tab = SettingsTab()
|
|
self.settings_tab = SettingsTab()
|