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所有修改完成!")