This commit is contained in:
zj
2026-02-03 03:25:29 +08:00
parent 30ab5711be
commit 10cc7d1c91
9 changed files with 1624 additions and 83 deletions

View File

@@ -16,6 +16,7 @@ class LvmOperations:
:param error_message: 命令失败时显示给用户的错误消息。
:param root_privilege: 如果为 True则使用 sudo 执行命令。
:param suppress_critical_dialog_on_stderr_match: 如果 stderr 包含此字符串,则不显示关键错误对话框。
可以是字符串或字符串元组/列表。
:param input_data: 传递给命令stdin的数据 (str)。
:return: (True/False, stdout_str, stderr_str)
"""
@@ -48,11 +49,24 @@ class LvmOperations:
logger.error(f"标准输出: {e.stdout.strip()}")
logger.error(f"标准错误: {stderr_output}")
if suppress_critical_dialog_on_stderr_match and \
suppress_critical_dialog_on_stderr_match in stderr_output:
# --- 修改开始:处理 suppress_critical_dialog_on_stderr_match 可以是字符串或元组/列表 ---
should_suppress_dialog = False
if suppress_critical_dialog_on_stderr_match:
if isinstance(suppress_critical_dialog_on_stderr_match, str):
if suppress_critical_dialog_on_stderr_match in stderr_output:
should_suppress_dialog = True
elif isinstance(suppress_critical_dialog_on_stderr_match, (list, tuple)):
for pattern in suppress_critical_dialog_on_stderr_match:
if pattern in stderr_output:
should_suppress_dialog = True
break # 找到一个匹配就足够了
if should_suppress_dialog:
logger.info(f"错误信息 '{stderr_output}' 匹配抑制条件,不显示关键错误对话框。")
else:
QMessageBox.critical(None, "错误", f"{error_message}\n错误详情: {stderr_output}")
# --- 修改结束 ---
return False, e.stdout.strip(), stderr_output
except FileNotFoundError:
QMessageBox.critical(None, "错误", f"命令 '{command_list[0]}' 未找到。请确保已安装相关工具。")
@@ -66,7 +80,7 @@ class LvmOperations:
def create_pv(self, device_path):
"""
创建物理卷 (PV)。
:param device_path: 设备的路径,例如 /dev/sdb1。
:param device_path: 设备的路径,例如 /dev/sdb1 或 /dev/sdb
:return: True 如果成功,否则 False。
"""
if not isinstance(device_path, str):
@@ -82,15 +96,58 @@ class LvmOperations:
return False
logger.info(f"尝试在 {device_path} 上创建物理卷。")
# 第一次尝试创建物理卷,抑制 "device is partitioned" 错误,因为我们将在代码中处理它
success, _, stderr = self._execute_shell_command(
["pvcreate", "-y", device_path], # -y 自动确认
f"{device_path} 上创建物理卷失败"
f"{device_path} 上创建物理卷失败",
suppress_critical_dialog_on_stderr_match="device is partitioned" # 抑制此特定错误
)
if success:
QMessageBox.information(None, "成功", f"物理卷已在 {device_path} 上成功创建。")
return True
else:
return False
# 如果 pvcreate 失败,检查是否是 "device is partitioned" 错误
if "device is partitioned" in stderr:
# 提示用户是否要擦除分区表
wipe_reply = QMessageBox.question(
None, "设备已分区",
f"设备 {device_path} 已分区。您是否要擦除设备上的所有分区表,"
f"并将其整个用于物理卷?此操作将导致所有数据丢失!",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
)
if wipe_reply == QMessageBox.Yes:
logger.warning(f"用户选择擦除 {device_path} 上的分区表并创建物理卷。")
# 尝试擦除分区表 (使用 GPT 作为默认,通常更现代且支持大容量磁盘)
# 注意:这里需要 parted 命令,确保系统已安装 parted
mklabel_success, _, mklabel_stderr = self._execute_shell_command(
["parted", "-s", device_path, "mklabel", "gpt"], # 使用 gpt 分区表
f"擦除 {device_path} 上的分区表失败"
)
if mklabel_success:
logger.info(f"已成功擦除 {device_path} 上的分区表。重试创建物理卷。")
# 再次尝试创建物理卷
retry_success, _, retry_stderr = self._execute_shell_command(
["pvcreate", "-y", device_path],
f"{device_path} 上创建物理卷失败 (重试)"
# 重试时不再抑制如果再次失败_execute_shell_command 会显示错误
)
if retry_success:
QMessageBox.information(None, "成功", f"物理卷已在 {device_path} 上成功创建。")
return True
else:
# 如果重试失败_execute_shell_command 已经显示错误
return False
else:
# mklabel 失败_execute_shell_command 已经显示错误
return False
else:
logger.info(f"用户取消了擦除 {device_path} 分区表的操作。")
QMessageBox.information(None, "信息", f"未在已分区设备 {device_path} 上创建物理卷。")
return False
else:
# 对于其他类型的 pvcreate 失败_execute_shell_command 已经显示了错误
return False
def delete_pv(self, device_path):
"""