fix: 适配MACOS多盘检测

This commit is contained in:
spiritlhl
2025-07-10 06:21:13 +00:00
parent b20175bfff
commit 37b4d23873
4 changed files with 127 additions and 65 deletions
+127 -57
View File
@@ -33,51 +33,59 @@ func getDiskInfo() ([]string, []string, []string, string, error) {
var currentDiskInfo *DiskSingelInfo
// macOS 特殊适配
if runtime.GOOS == "darwin" {
// 获取所有APFS卷的挂载点
mountPoints := getMacOSMountPoints()
for _, mountPoint := range mountPoints {
cmd := exec.Command("df", "-k", mountPoint)
output, err := cmd.Output()
if err != nil {
continue
// 获取 APFS 容器信息
containers := getMacOSAPFSContainers()
for _, container := range containers {
if container.TotalBytes >= 200*1024*1024*1024 {
diskInfos = append(diskInfos, container)
}
lines := strings.Split(string(output), "\n")
if len(lines) >= 2 {
fields := strings.Fields(lines[1])
if len(fields) >= 6 {
totalKB, err1 := strconv.ParseUint(fields[1], 10, 64)
usedKB, err2 := strconv.ParseUint(fields[2], 10, 64)
if err1 == nil && err2 == nil {
totalBytes := totalKB * 1024
usedBytes := usedKB * 1024
diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024)
diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024)
var diskTotalStr, diskUsageStr string
if diskTotalGB < 1 {
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
} else {
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
}
if diskUsageGB < 1 {
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
} else {
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
}
percentage := float64(usedBytes) / float64(totalBytes) * 100
percentageStr := strconv.FormatFloat(percentage, 'f', 1, 64) + "%%"
diskInfo := DiskSingelInfo{
TotalStr: diskTotalStr,
UsageStr: diskUsageStr,
PercentageStr: percentageStr,
BootPath: fields[0],
TotalBytes: totalBytes,
}
if mountPoint == "/" {
// 检查是否包含根分区
if container.BootPath != "" && (strings.Contains(container.BootPath, "disk3") || container.BootPath == "/" || currentDiskInfo == nil) {
bootPath = container.BootPath
currentDiskInfo = &container
}
}
// 如果没有找到包含根分区的容器,使用 df 命令作为fallback
if currentDiskInfo == nil {
cmd := exec.Command("df", "-k", "/")
output, err := cmd.Output()
if err == nil {
lines := strings.Split(string(output), "\n")
if len(lines) >= 2 {
fields := strings.Fields(lines[1])
if len(fields) >= 6 {
totalKB, err1 := strconv.ParseUint(fields[1], 10, 64)
usedKB, err2 := strconv.ParseUint(fields[2], 10, 64)
if err1 == nil && err2 == nil {
totalBytes := totalKB * 1024
usedBytes := usedKB * 1024
diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024)
diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024)
var diskTotalStr, diskUsageStr string
if diskTotalGB < 1 {
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
} else {
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
}
if diskUsageGB < 1 {
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
} else {
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
}
percentage := float64(usedBytes) / float64(totalBytes) * 100
percentageStr := strconv.FormatFloat(percentage, 'f', 1, 64) + "%%"
diskInfo := DiskSingelInfo{
TotalStr: diskTotalStr,
UsageStr: diskUsageStr,
PercentageStr: percentageStr,
BootPath: fields[0],
TotalBytes: totalBytes,
}
bootPath = fields[0]
currentDiskInfo = &diskInfo
}
if totalBytes >= 200*1024*1024*1024 {
diskInfos = append(diskInfos, diskInfo)
if totalBytes >= 200*1024*1024*1024 {
diskInfos = append(diskInfos, diskInfo)
}
}
}
}
@@ -288,30 +296,92 @@ func getDiskInfo() ([]string, []string, []string, string, error) {
return diskTotalStrs, diskUsageStrs, percentageStrs, bootPath, nil
}
// getMacOSMountPoints 获取macOS所有APFS卷的挂载点
func getMacOSMountPoints() []string {
var mountPoints []string
mountPoints = append(mountPoints, "/")
cmd := exec.Command("diskutil", "list")
// getMacOSAPFSContainers 获取macOS APFS容器信息
func getMacOSAPFSContainers() []DiskSingelInfo {
var containers []DiskSingelInfo
cmd := exec.Command("diskutil", "apfs", "list")
output, err := cmd.Output()
if err != nil {
return mountPoints
return containers
}
lines := strings.Split(string(output), "\n")
var currentContainer *DiskSingelInfo
var totalBytes, usedBytes uint64
var containerDisk string
for _, line := range lines {
if strings.Contains(line, "APFS Volume") && !strings.Contains(line, "Preboot") && !strings.Contains(line, "Recovery") && !strings.Contains(line, "VM") {
line = strings.TrimSpace(line)
if strings.Contains(line, "Container disk") {
if currentContainer != nil {
containers = append(containers, *currentContainer)
}
fields := strings.Fields(line)
if len(fields) >= 4 {
volumeName := fields[3]
if volumeName == "Macintosh" || volumeName == "Data" {
continue
if len(fields) >= 2 {
containerDisk = fields[1]
currentContainer = &DiskSingelInfo{
BootPath: containerDisk,
}
mountPoint := "/Volumes/" + volumeName
mountPoints = append(mountPoints, mountPoint)
}
} else if currentContainer != nil {
if strings.Contains(line, "Size (Capacity Ceiling):") {
parts := strings.Split(line, ":")
if len(parts) >= 2 {
sizeStr := strings.TrimSpace(parts[1])
if strings.Contains(sizeStr, " B ") {
sizeFields := strings.Fields(sizeStr)
if len(sizeFields) >= 1 {
if size, err := strconv.ParseUint(sizeFields[0], 10, 64); err == nil {
totalBytes = size
}
}
}
}
}
if strings.Contains(line, "Capacity In Use By Volumes:") {
parts := strings.Split(line, ":")
if len(parts) >= 2 {
usedStr := strings.TrimSpace(parts[1])
if strings.Contains(usedStr, " B ") {
usedFields := strings.Fields(usedStr)
if len(usedFields) >= 1 {
if used, err := strconv.ParseUint(usedFields[0], 10, 64); err == nil {
usedBytes = used
}
}
}
}
}
if strings.Contains(line, "Snapshot Mount Point:") && strings.Contains(line, "/") {
currentContainer.BootPath = containerDisk
}
}
if currentContainer != nil && totalBytes > 0 && usedBytes > 0 {
diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024)
diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024)
var diskTotalStr, diskUsageStr string
if diskTotalGB < 1 {
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
} else {
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
}
if diskUsageGB < 1 {
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
} else {
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
}
percentage := float64(usedBytes) / float64(totalBytes) * 100
percentageStr := strconv.FormatFloat(percentage, 'f', 1, 64) + "%%"
currentContainer.TotalStr = diskTotalStr
currentContainer.UsageStr = diskUsageStr
currentContainer.PercentageStr = percentageStr
currentContainer.TotalBytes = totalBytes
totalBytes = 0
usedBytes = 0
}
}
return mountPoints
if currentContainer != nil {
containers = append(containers, *currentContainer)
}
return containers
}
// parseSize 解析尺寸字符串为字节数
@@ -442,4 +512,4 @@ func isListContainsStr(list []string, str string) bool {
}
}
return false
}
}
-2
View File
@@ -15,13 +15,11 @@ func GetGPUModel() ([]string, error) {
if err != nil {
return nil, err
}
for _, card := range gi.GraphicsCards {
if card.DeviceInfo == nil {
return nil, errors.New("Cannot find device info")
}
gpuModel = append(gpuModel, card.DeviceInfo.Product.Name)
}
return gpuModel, nil
}
-3
View File
@@ -13,7 +13,6 @@ func extractGPUInfo(cmd *exec.Cmd) ([]string, error) {
if err != nil {
return nil, err
}
re := regexp.MustCompile(`"model"\s*=\s*["<]?"([^">]+)"[">]?`)
matches := re.FindAllSubmatch(gi, -1)
var modelNames []string
@@ -29,7 +28,6 @@ func GetGPUModel() ([]string, error) {
vendorNames := []string{
"AMD", "Intel", "Nvidia", "Apple",
}
ioreg := exec.Command("ioreg", "-rd1", "-c", "IOAccelerator")
gi, err := extractGPUInfo(ioreg)
if err != nil || len(gi) == 0 {
@@ -39,7 +37,6 @@ func GetGPUModel() ([]string, error) {
return nil, err
}
}
var gpuModel []string
for _, model := range gi {
for _, vendor := range vendorNames {
-3
View File
@@ -43,15 +43,12 @@ func GetGPUModel() ([]string, error) {
vendorNames := []string{
"AMD", "Intel", "Nvidia", "Apple",
}
key := C.CString("model")
defer C.free(unsafe.Pointer(key))
gi, err := extractGPUInfo(key)
if err != nil {
return nil, err
}
var gpuModel []string
for _, model := range gi {
for _, vendor := range vendorNames {