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
+126 -56
View File
@@ -33,51 +33,59 @@ func getDiskInfo() ([]string, []string, []string, string, error) {
var currentDiskInfo *DiskSingelInfo var currentDiskInfo *DiskSingelInfo
// macOS 特殊适配 // macOS 特殊适配
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
// 获取所有APFS卷的挂载点 // 获取 APFS 容器信息
mountPoints := getMacOSMountPoints() containers := getMacOSAPFSContainers()
for _, mountPoint := range mountPoints { for _, container := range containers {
cmd := exec.Command("df", "-k", mountPoint) if container.TotalBytes >= 200*1024*1024*1024 {
output, err := cmd.Output() diskInfos = append(diskInfos, container)
if err != nil {
continue
} }
lines := strings.Split(string(output), "\n") // 检查是否包含根分区
if len(lines) >= 2 { if container.BootPath != "" && (strings.Contains(container.BootPath, "disk3") || container.BootPath == "/" || currentDiskInfo == nil) {
fields := strings.Fields(lines[1]) bootPath = container.BootPath
if len(fields) >= 6 { currentDiskInfo = &container
totalKB, err1 := strconv.ParseUint(fields[1], 10, 64) }
usedKB, err2 := strconv.ParseUint(fields[2], 10, 64) }
if err1 == nil && err2 == nil { // 如果没有找到包含根分区的容器,使用 df 命令作为fallback
totalBytes := totalKB * 1024 if currentDiskInfo == nil {
usedBytes := usedKB * 1024 cmd := exec.Command("df", "-k", "/")
diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024) output, err := cmd.Output()
diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024) if err == nil {
var diskTotalStr, diskUsageStr string lines := strings.Split(string(output), "\n")
if diskTotalGB < 1 { if len(lines) >= 2 {
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB" fields := strings.Fields(lines[1])
} else { if len(fields) >= 6 {
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB" totalKB, err1 := strconv.ParseUint(fields[1], 10, 64)
} usedKB, err2 := strconv.ParseUint(fields[2], 10, 64)
if diskUsageGB < 1 { if err1 == nil && err2 == nil {
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB" totalBytes := totalKB * 1024
} else { usedBytes := usedKB * 1024
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB" diskTotalGB := float64(totalBytes) / (1024 * 1024 * 1024)
} diskUsageGB := float64(usedBytes) / (1024 * 1024 * 1024)
percentage := float64(usedBytes) / float64(totalBytes) * 100 var diskTotalStr, diskUsageStr string
percentageStr := strconv.FormatFloat(percentage, 'f', 1, 64) + "%%" if diskTotalGB < 1 {
diskInfo := DiskSingelInfo{ diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
TotalStr: diskTotalStr, } else {
UsageStr: diskUsageStr, diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
PercentageStr: percentageStr, }
BootPath: fields[0], if diskUsageGB < 1 {
TotalBytes: totalBytes, diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
} } else {
if mountPoint == "/" { 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] bootPath = fields[0]
currentDiskInfo = &diskInfo currentDiskInfo = &diskInfo
} if totalBytes >= 200*1024*1024*1024 {
if totalBytes >= 200*1024*1024*1024 { diskInfos = append(diskInfos, diskInfo)
diskInfos = append(diskInfos, diskInfo) }
} }
} }
} }
@@ -288,30 +296,92 @@ func getDiskInfo() ([]string, []string, []string, string, error) {
return diskTotalStrs, diskUsageStrs, percentageStrs, bootPath, nil return diskTotalStrs, diskUsageStrs, percentageStrs, bootPath, nil
} }
// getMacOSMountPoints 获取macOS所有APFS卷的挂载点 // getMacOSAPFSContainers 获取macOS APFS容器信息
func getMacOSMountPoints() []string { func getMacOSAPFSContainers() []DiskSingelInfo {
var mountPoints []string var containers []DiskSingelInfo
mountPoints = append(mountPoints, "/") cmd := exec.Command("diskutil", "apfs", "list")
cmd := exec.Command("diskutil", "list")
output, err := cmd.Output() output, err := cmd.Output()
if err != nil { if err != nil {
return mountPoints return containers
} }
lines := strings.Split(string(output), "\n") lines := strings.Split(string(output), "\n")
var currentContainer *DiskSingelInfo
var totalBytes, usedBytes uint64
var containerDisk string
for _, line := range lines { 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) fields := strings.Fields(line)
if len(fields) >= 4 { if len(fields) >= 2 {
volumeName := fields[3] containerDisk = fields[1]
if volumeName == "Macintosh" || volumeName == "Data" { currentContainer = &DiskSingelInfo{
continue 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 解析尺寸字符串为字节数 // parseSize 解析尺寸字符串为字节数
-2
View File
@@ -15,13 +15,11 @@ func GetGPUModel() ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, card := range gi.GraphicsCards { for _, card := range gi.GraphicsCards {
if card.DeviceInfo == nil { if card.DeviceInfo == nil {
return nil, errors.New("Cannot find device info") return nil, errors.New("Cannot find device info")
} }
gpuModel = append(gpuModel, card.DeviceInfo.Product.Name) gpuModel = append(gpuModel, card.DeviceInfo.Product.Name)
} }
return gpuModel, nil return gpuModel, nil
} }
-3
View File
@@ -13,7 +13,6 @@ func extractGPUInfo(cmd *exec.Cmd) ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
re := regexp.MustCompile(`"model"\s*=\s*["<]?"([^">]+)"[">]?`) re := regexp.MustCompile(`"model"\s*=\s*["<]?"([^">]+)"[">]?`)
matches := re.FindAllSubmatch(gi, -1) matches := re.FindAllSubmatch(gi, -1)
var modelNames []string var modelNames []string
@@ -29,7 +28,6 @@ func GetGPUModel() ([]string, error) {
vendorNames := []string{ vendorNames := []string{
"AMD", "Intel", "Nvidia", "Apple", "AMD", "Intel", "Nvidia", "Apple",
} }
ioreg := exec.Command("ioreg", "-rd1", "-c", "IOAccelerator") ioreg := exec.Command("ioreg", "-rd1", "-c", "IOAccelerator")
gi, err := extractGPUInfo(ioreg) gi, err := extractGPUInfo(ioreg)
if err != nil || len(gi) == 0 { if err != nil || len(gi) == 0 {
@@ -39,7 +37,6 @@ func GetGPUModel() ([]string, error) {
return nil, err return nil, err
} }
} }
var gpuModel []string var gpuModel []string
for _, model := range gi { for _, model := range gi {
for _, vendor := range vendorNames { for _, vendor := range vendorNames {
-3
View File
@@ -43,15 +43,12 @@ func GetGPUModel() ([]string, error) {
vendorNames := []string{ vendorNames := []string{
"AMD", "Intel", "Nvidia", "Apple", "AMD", "Intel", "Nvidia", "Apple",
} }
key := C.CString("model") key := C.CString("model")
defer C.free(unsafe.Pointer(key)) defer C.free(unsafe.Pointer(key))
gi, err := extractGPUInfo(key) gi, err := extractGPUInfo(key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var gpuModel []string var gpuModel []string
for _, model := range gi { for _, model := range gi {
for _, vendor := range vendorNames { for _, vendor := range vendorNames {