227 lines
9.1 KiB
Python
227 lines
9.1 KiB
Python
import os
|
|||
|
|
|
||
|
|
# 1. 给 SSHManager 添加 upload_directory 方法
|
||
|
|
ssh_path = "src/virtualbox_client/utils/ssh_manager.py"
|
||
|
|
with open(ssh_path, "r", encoding="utf-8") as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
old_method = """ def upload_file(self, local_path, remote_path):
|
||
|
|
\"\"\"上传本地文件到远程服务器,返回是否成功\"\"\"
|
||
|
|
client = self.get_ssh_client()
|
||
|
|
if not client:
|
||
|
|
return False
|
||
|
|
try:
|
||
|
|
sftp = client.open_sftp()
|
||
|
|
sftp.put(local_path, remote_path)
|
||
|
|
sftp.close()
|
||
|
|
print(f\"✔ 上传成功: {local_path} -> {remote_path}\")
|
||
|
|
return True
|
||
|
|
except Exception as e:
|
||
|
|
if self._cancelled.is_set():
|
||
|
|
return False
|
||
|
|
print(f\"✘ 上传失败: {e}\")
|
||
|
|
return False
|
||
|
|
"""
|
||
|
|
|
||
|
|
new_method = """ def upload_file(self, local_path, remote_path):
|
||
|
|
\"\"\"上传本地文件到远程服务器,返回是否成功\"\"\"
|
||
|
|
client = self.get_ssh_client()
|
||
|
|
if not client:
|
||
|
|
return False
|
||
|
|
try:
|
||
|
|
sftp = client.open_sftp()
|
||
|
|
sftp.put(local_path, remote_path)
|
||
|
|
sftp.close()
|
||
|
|
print(f\"✔ 上传成功: {local_path} -> {remote_path}\")
|
||
|
|
return True
|
||
|
|
except Exception as e:
|
||
|
|
if self._cancelled.is_set():
|
||
|
|
return False
|
||
|
|
print(f\"✘ 上传失败: {e}\")
|
||
|
|
return False
|
||
|
|
|
||
|
|
def upload_directory(self, local_dir, remote_dir):
|
||
|
|
\"\"\"递归上传整个文件夹到远程服务器,返回是否成功\"\"\"
|
||
|
|
import os as _os
|
||
|
|
client = self.get_ssh_client()
|
||
|
|
if not client:
|
||
|
|
return False
|
||
|
|
try:
|
||
|
|
sftp = client.open_sftp()
|
||
|
|
local_dir = _os.path.normpath(local_dir)
|
||
|
|
remote_dir = remote_dir.rstrip('/')
|
||
|
|
# 创建远程根目录
|
||
|
|
self.exec_command(f'mkdir -p \"{remote_dir}\"')
|
||
|
|
for root, dirs, files in _os.walk(local_dir):
|
||
|
|
# 计算相对路径
|
||
|
|
rel_path = _os.path.relpath(root, local_dir)
|
||
|
|
if rel_path == '.':
|
||
|
|
rel_path = ''
|
||
|
|
# 创建远程子目录
|
||
|
|
target_dir = remote_dir + ('/' + rel_path.replace('\\\\', '/') if rel_path else '')
|
||
|
|
self.exec_command(f'mkdir -p \"{target_dir}\"')
|
||
|
|
for fname in files:
|
||
|
|
if self._cancelled.is_set():
|
||
|
|
sftp.close()
|
||
|
|
return False
|
||
|
|
local_file = _os.path.join(root, fname)
|
||
|
|
remote_file = target_dir + '/' + fname
|
||
|
|
sftp.put(local_file, remote_file)
|
||
|
|
print(f\" ✔ {local_file} -> {remote_file}\")
|
||
|
|
sftp.close()
|
||
|
|
print(f\"✔ 文件夹上传成功: {local_dir} -> {remote_dir}\")
|
||
|
|
return True
|
||
|
|
except Exception as e:
|
||
|
|
if self._cancelled.is_set():
|
||
|
|
return False
|
||
|
|
print(f\"✘ 文件夹上传失败: {e}\")
|
||
|
|
return False
|
||
|
|
"""
|
||
|
|
|
||
|
|
content = content.replace(old_method, new_method)
|
||
|
|
with open(ssh_path, "w", encoding="utf-8") as f:
|
||
|
|
f.write(content)
|
||
|
|
print("✅ SSHManager 已添加 upload_directory")
|
||
|
|
|
||
|
|
# 2. 给 VBoxSSHManager 添加 upload_directory 方法
|
||
|
|
vbox_path = "src/virtualbox_client/utils/vbox_ssh_manager.py"
|
||
|
|
with open(vbox_path, "r", encoding="utf-8") as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
content = content.replace(old_method, new_method)
|
||
|
|
with open(vbox_path, "w", encoding="utf-8") as f:
|
||
|
|
f.write(content)
|
||
|
|
print("✅ VBoxSSHManager 已添加 upload_directory")
|
||
|
|
|
||
|
|
# 3. 修改 gui.py - 添加上传文件夹功能
|
||
|
|
gui_path = "src/virtualbox_client/gui.py"
|
||
|
|
with open(gui_path, "r", encoding="utf-8") as f:
|
||
|
|
content = f.read()
|
||
|
|
|
||
|
|
# 在 WorkspaceWorker 中添加 OPERATION_UPLOAD_DIR
|
||
|
|
old_op = ' OPERATION_UPLOAD = "upload"\n'
|
||
|
|
new_op = ' OPERATION_UPLOAD = "upload"\n OPERATION_UPLOAD_DIR = "upload_dir"\n'
|
||
|
|
content = content.replace(old_op, new_op)
|
||
|
|
|
||
|
|
# 在 run 方法中添加分支
|
||
|
|
old_run = """ elif self.operation == WorkspaceWorker.OPERATION_UPLOAD:
|
||
|
|
result = self._upload_file(vm)"""
|
||
|
|
new_run = """ elif self.operation == WorkspaceWorker.OPERATION_UPLOAD:
|
||
|
|
result = self._upload_file(vm)
|
||
|
|
elif self.operation == WorkspaceWorker.OPERATION_UPLOAD_DIR:
|
||
|
|
result = self._upload_directory(vm)"""
|
||
|
|
content = content.replace(old_run, new_run)
|
||
|
|
|
||
|
|
# 在 _upload_file 之后添加 _upload_directory 方法
|
||
|
|
old_upload = """ def _upload_file(self, vm) -> bool:
|
||
|
|
local_path = self.kwargs.get("local_path", "")
|
||
|
|
remote_path = self.kwargs.get("remote_path", "")
|
||
|
|
if not local_path or not remote_path:
|
||
|
|
return False
|
||
|
|
remote_dir = remote_path.rsplit('/', 1)[0] if '/' in remote_path else remote_path.rsplit('\\\\', 1)[0]
|
||
|
|
vm.exec_command(f'mkdir -p "{remote_dir}"')
|
||
|
|
return vm.upload_file(local_path, remote_path)"""
|
||
|
|
|
||
|
|
new_upload = """ def _upload_file(self, vm) -> bool:
|
||
|
|
local_path = self.kwargs.get("local_path", "")
|
||
|
|
remote_path = self.kwargs.get("remote_path", "")
|
||
|
|
if not local_path or not remote_path:
|
||
|
|
return False
|
||
|
|
remote_dir = remote_path.rsplit('/', 1)[0] if '/' in remote_path else remote_path.rsplit('\\\\', 1)[0]
|
||
|
|
vm.exec_command(f'mkdir -p "{remote_dir}"')
|
||
|
|
return vm.upload_file(local_path, remote_path)
|
||
|
|
|
||
|
|
def _upload_directory(self, vm) -> bool:
|
||
|
|
local_dir = self.kwargs.get("local_path", "")
|
||
|
|
remote_dir = self.kwargs.get("remote_path", "")
|
||
|
|
if not local_dir or not remote_dir:
|
||
|
|
return False
|
||
|
|
return vm.upload_directory(local_dir, remote_dir)"""
|
||
|
|
|
||
|
|
content = content.replace(old_upload, new_upload)
|
||
|
|
|
||
|
|
# 修改 _on_worker_finished 添加 UPLOAD_DIR 处理
|
||
|
|
old_finish = """ elif (
|
||
|
|
self._worker and self._worker.operation == WorkspaceWorker.OPERATION_UPLOAD
|
||
|
|
):
|
||
|
|
if result:
|
||
|
|
self.log_panel.append_log("✅ 上传成功", "success")
|
||
|
|
else:
|
||
|
|
self.log_panel.append_log("❌ 上传失败", "error")
|
||
|
|
QTimer.singleShot(500, self._soft_refresh)"""
|
||
|
|
|
||
|
|
new_finish = """ elif (
|
||
|
|
self._worker
|
||
|
|
and self._worker.operation
|
||
|
|
in (WorkspaceWorker.OPERATION_UPLOAD, WorkspaceWorker.OPERATION_UPLOAD_DIR)
|
||
|
|
):
|
||
|
|
if result:
|
||
|
|
self.log_panel.append_log("✅ 上传成功", "success")
|
||
|
|
else:
|
||
|
|
self.log_panel.append_log("❌ 上传失败", "error")
|
||
|
|
QTimer.singleShot(500, self._soft_refresh)"""
|
||
|
|
|
||
|
|
content = content.replace(old_finish, new_finish)
|
||
|
|
|
||
|
|
# 在 WorkspacePanel.setup_ui 的工具栏中添加"上传文件夹"按钮
|
||
|
|
old_upload_btn = """ self.upload_btn = QPushButton("📤 上传文件")"""
|
||
|
|
new_upload_btn = """ self.upload_btn = QPushButton("📤 上传文件")"""
|
||
|
|
# 保持原样,在后面添加新按钮
|
||
|
|
# 在 upload_btn 后面添加 upload_dir_btn
|
||
|
|
old_toolbar = """ toolbar.addWidget(self.upload_btn)
|
||
|
|
|
||
|
|
self.mkdir_btn = QPushButton("📂 新建文件夹")"""
|
||
|
|
new_toolbar = """ toolbar.addWidget(self.upload_btn)
|
||
|
|
|
||
|
|
self.upload_dir_btn = QPushButton("📁 上传文件夹")
|
||
|
|
self.upload_dir_btn.setStyleSheet(\"\"\"
|
||
|
|
QPushButton { background-color: #16a085; color: white; padding: 6px 14px;
|
||
|
|
font-size: 12px; font-weight: bold; border: none; border-radius: 4px; }
|
||
|
|
QPushButton:hover { background-color: #1abc9c; }
|
||
|
|
QPushButton:disabled { background-color: #555; color: #999; }
|
||
|
|
\"\"\")
|
||
|
|
self.upload_dir_btn.clicked.connect(self._upload_folder_to_workspace)
|
||
|
|
toolbar.addWidget(self.upload_dir_btn)
|
||
|
|
|
||
|
|
self.mkdir_btn = QPushButton("📂 新建文件夹")"""
|
||
|
|
content = content.replace(old_toolbar, new_toolbar)
|
||
|
|
|
||
|
|
# 更新 _set_busy 禁用 upload_dir_btn
|
||
|
|
old_set_busy = """ self.upload_btn.setEnabled(not busy)
|
||
|
|
self.mkdir_btn.setEnabled(not busy)
|
||
|
|
self.home_btn.setEnabled(not busy)"""
|
||
|
|
new_set_busy = """ self.upload_btn.setEnabled(not busy)
|
||
|
|
self.upload_dir_btn.setEnabled(not busy)
|
||
|
|
self.mkdir_btn.setEnabled(not busy)
|
||
|
|
self.home_btn.setEnabled(not busy)"""
|
||
|
|
content = content.replace(old_set_busy, new_set_busy)
|
||
|
|
|
||
|
|
# 在 _upload_to_workspace 方法之后添加 _upload_folder_to_workspace
|
||
|
|
old_upload_workspace = """ def _upload_to_workspace(self):"""
|
||
|
|
|
||
|
|
new_upload_workspace = """ def _upload_folder_to_workspace(self):
|
||
|
|
if not self._config_panel or not self._validate_ssh_config():
|
||
|
|
return
|
||
|
|
|
||
|
|
local_dir = QFileDialog.getExistingDirectory(self, "选择要上传到工作区的文件夹")
|
||
|
|
if not local_dir:
|
||
|
|
return
|
||
|
|
|
||
|
|
folder_name = os.path.basename(local_dir.rstrip('/\\\\'))
|
||
|
|
remote_path = f"~/workspace/{folder_name}"
|
||
|
|
self._start_worker(
|
||
|
|
WorkspaceWorker.OPERATION_UPLOAD_DIR,
|
||
|
|
local_path=local_dir,
|
||
|
|
remote_path=remote_path,
|
||
|
|
)
|
||
|
|
|
||
|
|
def _upload_to_workspace(self):"""
|
||
|
|
|
||
|
|
content = content.replace(old_upload_workspace, new_upload_workspace)
|
||
|
|
|
||
|
|
with open(gui_path, "w", encoding="utf-8") as f:
|
||
|
|
f.write(content)
|
||
|
|
print("✅ gui.py 已添加上传文件夹功能")
|
||
|
|
|
||
|
|
print("\\n所有修改完成!")
|