fix: 修复MACOS的信息识别

This commit is contained in:
spiritlhl
2025-06-28 13:39:57 +00:00
parent 830debc979
commit 146ce6074d
7 changed files with 143 additions and 60 deletions

View File

@@ -27,7 +27,7 @@ jobs:
run: | run: |
git config --global user.name 'github-actions' git config --global user.name 'github-actions'
git config --global user.email 'github-actions@github.com' git config --global user.email 'github-actions@github.com'
TAG="v0.0.12-$(date +'%Y%m%d%H%M%S')" TAG="v0.0.13-$(date +'%Y%m%d%H%M%S')"
git tag $TAG git tag $TAG
git push origin $TAG git push origin $TAG
echo "TAG=$TAG" >> $GITHUB_ENV echo "TAG=$TAG" >> $GITHUB_ENV

View File

@@ -15,10 +15,7 @@ Include: https://github.com/oneclickvirt/gostun
- [x] 适配```MacOS```与```Windows```系统的信息查询 - [x] 适配```MacOS```与```Windows```系统的信息查询
- [x] 部分Windows10系统下打勾打叉编码错误显示已判断是Win时使用Y/N显示而不是勾叉 - [x] 部分Windows10系统下打勾打叉编码错误显示已判断是Win时使用Y/N显示而不是勾叉
- [x] 检测GPU相关信息参考[ghw](https://github.com/jaypipes/ghw) - [x] 检测GPU相关信息参考[ghw](https://github.com/jaypipes/ghw)
- [x] 适配MACOS系统的相关信息识别
## TODO
- [ ] 适配MACOS系统的相关信息识别
## Usage ## Usage

View File

@@ -1,6 +1,6 @@
package model package model
const BasicsVersion = "v0.0.12" const BasicsVersion = "v0.0.13"
var EnableLoger bool var EnableLoger bool

View File

@@ -12,7 +12,27 @@ import (
// getDiskInfo 获取硬盘信息 // getDiskInfo 获取硬盘信息
func getDiskInfo() (string, string, string, string, error) { func getDiskInfo() (string, string, string, string, error) {
var diskTotalStr, diskUsageStr, percentageStr, bootPath string var diskTotalStr, diskUsageStr, percentageStr, bootPath string
// macOS 特殊适配
if runtime.GOOS == "darwin" {
cmd := exec.Command("df", "-h", "/")
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) >= 5 {
bootPath = fields[0]
diskTotalStr = fields[1]
diskUsageStr = fields[2]
percentageStr = fields[4]
if strings.Contains(percentageStr, "%") {
percentageStr = strings.ReplaceAll(percentageStr, "%", "%%")
}
return diskTotalStr, diskUsageStr, percentageStr, bootPath, nil
}
}
}
}
// BSD系统特殊处理 // BSD系统特殊处理
if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "netbsd" { if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "netbsd" {
cmd := exec.Command("df", "-h", "/") cmd := exec.Command("df", "-h", "/")
@@ -26,24 +46,17 @@ func getDiskInfo() (string, string, string, string, error) {
diskTotalStr = fields[1] diskTotalStr = fields[1]
diskUsageStr = fields[2] diskUsageStr = fields[2]
percentageStr = fields[4] percentageStr = fields[4]
// 两个%避免被转义
if percentageStr != "" && strings.Contains(percentageStr, "%") { if percentageStr != "" && strings.Contains(percentageStr, "%") {
percentageStr = strings.ReplaceAll(percentageStr, "%", "%%") percentageStr = strings.ReplaceAll(percentageStr, "%", "%%")
} }
return diskTotalStr, diskUsageStr, percentageStr, bootPath, nil return diskTotalStr, diskUsageStr, percentageStr, bootPath, nil
} }
} }
} }
} }
// 保持原有代码逻辑
tempDiskTotal, tempDiskUsage := getDiskTotalAndUsed() tempDiskTotal, tempDiskUsage := getDiskTotalAndUsed()
diskTotalGB := float64(tempDiskTotal) / (1024 * 1024 * 1024) diskTotalGB := float64(tempDiskTotal) / (1024 * 1024 * 1024)
diskUsageGB := float64(tempDiskUsage) / (1024 * 1024 * 1024) diskUsageGB := float64(tempDiskUsage) / (1024 * 1024 * 1024)
// 字节为单位 进行单位转换
if diskTotalGB < 1 { if diskTotalGB < 1 {
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB" diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
} else { } else {
@@ -54,7 +67,6 @@ func getDiskInfo() (string, string, string, string, error) {
} else { } else {
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB" diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
} }
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
parts, err := disk.Partitions(true) parts, err := disk.Partitions(true)
if err != nil { if err != nil {
@@ -76,7 +88,6 @@ func getDiskInfo() (string, string, string, string, error) {
} }
} else { } else {
// 特殊处理 docker、lxc 等虚拟化使用 overlay 挂载的情况 // 特殊处理 docker、lxc 等虚拟化使用 overlay 挂载的情况
// df -x tmpfs / | awk "NR>1" | sed ":a;N;s/\\n//g;ta" | awk '{print $1}'
cmd := exec.Command("df", "-x", "tmpfs", "/") cmd := exec.Command("df", "-x", "tmpfs", "/")
output, err := cmd.Output() output, err := cmd.Output()
if err == nil { if err == nil {
@@ -115,8 +126,6 @@ func getDiskInfo() (string, string, string, string, error) {
} }
} }
} }
// 两个%避免被转义
if percentageStr != "" && strings.Contains(percentageStr, "%") { if percentageStr != "" && strings.Contains(percentageStr, "%") {
percentageStr = strings.ReplaceAll(percentageStr, "%", "%%") percentageStr = strings.ReplaceAll(percentageStr, "%", "%%")
} }
@@ -124,6 +133,26 @@ func getDiskInfo() (string, string, string, string, error) {
} }
func getDiskTotalAndUsed() (total uint64, used uint64) { func getDiskTotalAndUsed() (total uint64, used uint64) {
// MacOS特殊处理直接用 df -k /
if runtime.GOOS == "darwin" {
cmd := exec.Command("df", "-k", "/")
out, err := cmd.CombinedOutput()
if err == nil {
lines := strings.Split(string(out), "\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 {
total = totalKB * 1024
used = usedKB * 1024
return
}
}
}
}
}
devices := make(map[string]string) devices := make(map[string]string)
// 使用默认过滤规则 // 使用默认过滤规则
diskList, _ := disk.Partitions(false) diskList, _ := disk.Partitions(false)
@@ -141,18 +170,15 @@ func getDiskTotalAndUsed() (total uint64, used uint64) {
used += diskUsageOf.Used used += diskUsageOf.Used
} }
} }
// 回退到根路径的获取方法
// Fallback 到根路径的获取方法
if total == 0 && used == 0 { if total == 0 && used == 0 {
var cmd *exec.Cmd var cmd *exec.Cmd
// BSD系统使用特定参数 // BSD系统使用特定参数
if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "netbsd" { if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" || runtime.GOOS == "netbsd" {
cmd = exec.Command("df", "-k", "/") cmd = exec.Command("df", "-k", "/")
} else { } else {
cmd = exec.Command("df") cmd = exec.Command("df")
} }
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err == nil { if err == nil {
s := strings.Split(string(out), "\n") s := strings.Split(string(out), "\n")

View File

@@ -168,9 +168,44 @@ func getHostInfo() (string, string, string, string, string, string, string, stri
// MAC需要额外获取信息进行判断 // MAC需要额外获取信息进行判断
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
if len(model.MacOSInfo) > 0 { if len(model.MacOSInfo) > 0 {
var modelName, modelIdentifier, chip, vendor string
for _, line := range model.MacOSInfo { for _, line := range model.MacOSInfo {
if strings.Contains(line, "Model Name") { if strings.Contains(line, "Model Name") {
VmType = strings.TrimSpace(strings.Split(line, ":")[1]) modelName = strings.TrimSpace(strings.SplitN(line, ":", 2)[1])
} else if strings.Contains(line, "Model Identifier") {
modelIdentifier = strings.TrimSpace(strings.SplitN(line, ":", 2)[1])
} else if strings.Contains(line, "Chip") {
chip = strings.TrimSpace(strings.SplitN(line, ":", 2)[1])
} else if strings.Contains(line, "Manufacturer") || strings.Contains(line, "Vendor") {
vendor = strings.TrimSpace(strings.SplitN(line, ":", 2)[1])
}
}
allInfo := strings.ToLower(modelName + " " + modelIdentifier + " " + chip + " " + vendor)
virtualKeywords := []string{"vmware", "virtualbox", "parallels", "qemu", "microsoft", "xen"}
isVirtual := false
for _, key := range virtualKeywords {
if strings.Contains(allInfo, key) {
isVirtual = true
break
}
}
physicalWhitelist := []string{"mac mini", "macbook pro", "macbook air", "imac", "mac studio", "mac pro"}
if isVirtual {
VmType = "virtual"
} else {
foundPhysical := false
for _, p := range physicalWhitelist {
if strings.HasPrefix(strings.ToLower(modelName), p) {
foundPhysical = true
break
}
}
if foundPhysical {
VmType = "physical"
} else if modelName == "" {
VmType = "unknown"
} else {
VmType = modelName
} }
} }
} }

View File

@@ -1,7 +1,9 @@
package system package system
import ( import (
"fmt"
"os" "os"
"os/exec"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
@@ -19,33 +21,33 @@ func getMemoryInfo() (string, string, string, string, string, string) {
memoryTotal := float64(mv.Total) memoryTotal := float64(mv.Total)
memoryUsage := float64(mv.Total - mv.Available) memoryUsage := float64(mv.Total - mv.Available)
if memoryTotal < 1024*1024*1024 { if memoryTotal < 1024*1024*1024 {
memoryTotalStr = strconv.FormatFloat(memoryTotal/(1024*1024), 'f', 2, 64) + " MB" memoryTotalStr = fmt.Sprintf("%.2f MB", memoryTotal/(1024*1024))
} else { } else {
memoryTotalStr = strconv.FormatFloat(memoryTotal/(1024*1024*1024), 'f', 2, 64) + " GB" memoryTotalStr = fmt.Sprintf("%.2f GB", memoryTotal/(1024*1024*1024))
} }
if memoryUsage < 1024*1024*1024 { if memoryUsage < 1024*1024*1024 {
memoryUsageStr = strconv.FormatFloat(memoryUsage/(1024*1024), 'f', 2, 64) + " MB" memoryUsageStr = fmt.Sprintf("%.2f MB", memoryUsage/(1024*1024))
} else { } else {
memoryUsageStr = strconv.FormatFloat(memoryUsage/(1024*1024*1024), 'f', 2, 64) + " GB" memoryUsageStr = fmt.Sprintf("%.2f GB", memoryUsage/(1024*1024*1024))
} }
if runtime.GOOS != "windows" { if runtime.GOOS != "windows" && runtime.GOOS != "darwin" {
swapTotal := float64(mv.SwapTotal) swapTotal := float64(mv.SwapTotal)
swapUsage := float64(mv.SwapTotal - mv.SwapFree) swapUsage := float64(mv.SwapTotal - mv.SwapFree)
if swapTotal != 0 { if swapTotal != 0 {
if swapTotal < 1024*1024*1024 { if swapTotal < 1024*1024*1024 {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024), 'f', 2, 64) + " MB" swapTotalStr = fmt.Sprintf("%.2f MB", swapTotal/(1024*1024))
} else { } else {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024*1024), 'f', 2, 64) + " GB" swapTotalStr = fmt.Sprintf("%.2f GB", swapTotal/(1024*1024*1024))
} }
if swapUsage < 1024*1024*1024 { if swapUsage < 1024*1024*1024 {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024), 'f', 2, 64) + " MB" swapUsageStr = fmt.Sprintf("%.2f MB", swapUsage/(1024*1024))
} else { } else {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024*1024), 'f', 2, 64) + " GB" swapUsageStr = fmt.Sprintf("%.2f GB", swapUsage/(1024*1024*1024))
} }
} }
} }
} }
// MAC需要额外获取信息进行判断 // macOS 特殊处理:内存和 swap
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
if len(model.MacOSInfo) > 0 { if len(model.MacOSInfo) > 0 {
for _, line := range model.MacOSInfo { for _, line := range model.MacOSInfo {
@@ -54,9 +56,30 @@ func getMemoryInfo() (string, string, string, string, string, string) {
} }
} }
} }
output, err := exec.Command("sysctl", "vm.swapusage").Output()
if err == nil {
// 输出示例: "vm.swapusage: total = 2048.00M used = 1021.25M free = 1026.75M (encrypted)"
fields := strings.Fields(string(output))
if len(fields) >= 7 {
totalVal, err1 := strconv.ParseFloat(strings.TrimSuffix(fields[3], "M"), 64)
usedVal, err2 := strconv.ParseFloat(strings.TrimSuffix(fields[6], "M"), 64)
if err1 == nil && err2 == nil {
if totalVal >= 1024 {
swapTotalStr = fmt.Sprintf("%.2f GB", totalVal/1024)
} else {
swapTotalStr = fmt.Sprintf("%.2f MB", totalVal)
}
if usedVal >= 1024 {
swapUsageStr = fmt.Sprintf("%.2f GB", usedVal/1024)
} else {
swapUsageStr = fmt.Sprintf("%.2f MB", usedVal)
}
}
}
}
} }
// Windows 特殊处理 swapgopsutil 的 VirtualMemory 在 Win 上不准确)
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
// gopsutil 在 Windows 下不能正确取 swap
ms, err := mem.SwapMemory() ms, err := mem.SwapMemory()
if err != nil { if err != nil {
println("mem.SwapMemory error:", err) println("mem.SwapMemory error:", err)
@@ -65,26 +88,25 @@ func getMemoryInfo() (string, string, string, string, string, string) {
swapUsage := float64(ms.Used) swapUsage := float64(ms.Used)
if swapTotal != 0 { if swapTotal != 0 {
if swapTotal < 1024*1024*1024 { if swapTotal < 1024*1024*1024 {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024), 'f', 2, 64) + " MB" swapTotalStr = fmt.Sprintf("%.2f MB", swapTotal/(1024*1024))
} else { } else {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024*1024), 'f', 2, 64) + " GB" swapTotalStr = fmt.Sprintf("%.2f GB", swapTotal/(1024*1024*1024))
} }
if swapUsage < 1024*1024*1024 { if swapUsage < 1024*1024*1024 {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024), 'f', 2, 64) + " MB" swapUsageStr = fmt.Sprintf("%.2f MB", swapUsage/(1024*1024))
} else { } else {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024*1024), 'f', 2, 64) + " GB" swapUsageStr = fmt.Sprintf("%.2f GB", swapUsage/(1024*1024*1024))
} }
} }
} }
} }
// virtio_balloon 检测Linux
virtioBalloon, err := os.ReadFile("/proc/modules") virtioBalloon, err := os.ReadFile("/proc/modules")
if err == nil { if err == nil && strings.Contains(string(virtioBalloon), "virtio_balloon") {
if strings.Contains(string(virtioBalloon), "virtio_balloon") { if runtime.GOOS == "windows" {
if runtime.GOOS == "windows" { virtioBalloonStatus = "[Y] Enabled"
virtioBalloonStatus = "[Y] Enabled" } else {
} else { virtioBalloonStatus = "✔️ Enabled"
virtioBalloonStatus = "✔️ Enabled"
}
} }
} }
if virtioBalloonStatus == "" { if virtioBalloonStatus == "" {
@@ -94,14 +116,13 @@ func getMemoryInfo() (string, string, string, string, string, string) {
virtioBalloonStatus = "❌ Undetected" virtioBalloonStatus = "❌ Undetected"
} }
} }
// KSM 状态检测Linux
ksmStatus, err := os.ReadFile("/sys/kernel/mm/ksm/run") ksmStatus, err := os.ReadFile("/sys/kernel/mm/ksm/run")
if err == nil { if err == nil && strings.Contains(string(ksmStatus), "1") {
if strings.Contains(string(ksmStatus), "1") { if runtime.GOOS == "windows" {
if runtime.GOOS == "windows" { KernelSamepageMerging = "[Y] Enabled"
KernelSamepageMerging = "[Y] Enabled" } else {
} else { KernelSamepageMerging = "✔️ Enabled"
KernelSamepageMerging = "✔️ Enabled"
}
} }
} }
if KernelSamepageMerging == "" { if KernelSamepageMerging == "" {

View File

@@ -78,15 +78,17 @@ func CheckSystemInfo(language string) string {
res += " GPU Stats : " + ret.GpuStats + "\n" res += " GPU Stats : " + ret.GpuStats + "\n"
} }
} }
if runtime.GOOS != "windows" && runtime.GOOS != "macos" { if runtime.GOOS != "windows" && runtime.GOOS != "darwin" {
res += " AES-NI : " + ret.CpuAesNi + "\n" res += " AES-NI : " + ret.CpuAesNi + "\n"
} }
res += " VM-x/AMD-V/Hyper-V : " + ret.CpuVAH + "\n" if runtime.GOOS != "darwin" {
res += " VM-x/AMD-V/Hyper-V : " + ret.CpuVAH + "\n"
}
res += " RAM : " + ret.MemoryUsage + " / " + ret.MemoryTotal + "\n" res += " RAM : " + ret.MemoryUsage + " / " + ret.MemoryTotal + "\n"
if ret.VirtioBalloon != "" { if ret.VirtioBalloon != "" && runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
res += " Virtio Balloon : " + ret.VirtioBalloon + "\n" res += " Virtio Balloon : " + ret.VirtioBalloon + "\n"
} }
if ret.KSM != "" { if ret.KSM != "" && runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
res += " KSM : " + ret.KSM + "\n" res += " KSM : " + ret.KSM + "\n"
} }
if ret.SwapTotal == "" && ret.SwapUsage == "" { if ret.SwapTotal == "" && ret.SwapUsage == "" {
@@ -128,15 +130,17 @@ func CheckSystemInfo(language string) string {
res += " GPU 状态 : " + ret.GpuStats + "\n" res += " GPU 状态 : " + ret.GpuStats + "\n"
} }
} }
if runtime.GOOS != "windows" && runtime.GOOS != "macos" { if runtime.GOOS != "windows" && runtime.GOOS != "darwin" {
res += " AES-NI : " + ret.CpuAesNi + "\n" res += " AES-NI : " + ret.CpuAesNi + "\n"
} }
res += " VM-x/AMD-V/Hyper-V : " + ret.CpuVAH + "\n" if runtime.GOOS != "darwin" {
res += " VM-x/AMD-V/Hyper-V : " + ret.CpuVAH + "\n"
}
res += " 内存 : " + ret.MemoryUsage + " / " + ret.MemoryTotal + "\n" res += " 内存 : " + ret.MemoryUsage + " / " + ret.MemoryTotal + "\n"
if ret.VirtioBalloon != "" { if ret.VirtioBalloon != "" && runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
res += " 气球驱动 : " + ret.VirtioBalloon + "\n" res += " 气球驱动 : " + ret.VirtioBalloon + "\n"
} }
if ret.KSM != "" { if ret.KSM != "" && runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
res += " 内核页合并 : " + ret.KSM + "\n" res += " 内核页合并 : " + ret.KSM + "\n"
} }
if ret.SwapTotal == "" && ret.SwapUsage == "" { if ret.SwapTotal == "" && ret.SwapUsage == "" {