mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-03-05 20:49:04 -08:00
fix(windows): use GlobalMemoryStatusEx for memory
resolves #3272 resolves #3514
This commit is contained in:
parent
9d6f2d938b
commit
23148ea823
|
@ -273,3 +273,8 @@ func (env *MockedEnvironment) CursorPosition() (int, int) {
|
||||||
args := env.Called()
|
args := env.Called()
|
||||||
return args.Int(0), args.Int(1)
|
return args.Int(0), args.Int(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (env *MockedEnvironment) SystemInfo() (*platform.SystemInfo, error) {
|
||||||
|
args := env.Called()
|
||||||
|
return args.Get(0).(*platform.SystemInfo), args.Error(1)
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@ import (
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/platform/cmd"
|
"github.com/jandedobbeleer/oh-my-posh/src/platform/cmd"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
"github.com/jandedobbeleer/oh-my-posh/src/regex"
|
||||||
|
|
||||||
|
cpu "github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
disk "github.com/shirou/gopsutil/v3/disk"
|
||||||
|
load "github.com/shirou/gopsutil/v3/load"
|
||||||
process "github.com/shirou/gopsutil/v3/process"
|
process "github.com/shirou/gopsutil/v3/process"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -133,6 +136,30 @@ type Connection struct {
|
||||||
SSID string // Wi-Fi only
|
SSID string // Wi-Fi only
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Memory struct {
|
||||||
|
PhysicalTotalMemory uint64
|
||||||
|
PhysicalAvailableMemory uint64
|
||||||
|
PhysicalFreeMemory uint64
|
||||||
|
PhysicalPercentUsed float64
|
||||||
|
SwapTotalMemory uint64
|
||||||
|
SwapFreeMemory uint64
|
||||||
|
SwapPercentUsed float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type SystemInfo struct {
|
||||||
|
// mem
|
||||||
|
Memory
|
||||||
|
// cpu
|
||||||
|
Times float64
|
||||||
|
CPU []cpu.InfoStat
|
||||||
|
// load
|
||||||
|
Load1 float64
|
||||||
|
Load5 float64
|
||||||
|
Load15 float64
|
||||||
|
// disk
|
||||||
|
Disks map[string]disk.IOCountersStat
|
||||||
|
}
|
||||||
|
|
||||||
type SegmentsCache map[string]interface{}
|
type SegmentsCache map[string]interface{}
|
||||||
|
|
||||||
func (s *SegmentsCache) Contains(key string) bool {
|
func (s *SegmentsCache) Contains(key string) bool {
|
||||||
|
@ -218,6 +245,7 @@ type Environment interface {
|
||||||
LoadTemplateCache()
|
LoadTemplateCache()
|
||||||
SetPromptCount()
|
SetPromptCount()
|
||||||
CursorPosition() (row, col int)
|
CursorPosition() (row, col int)
|
||||||
|
SystemInfo() (*SystemInfo, error)
|
||||||
Debug(message string)
|
Debug(message string)
|
||||||
Error(err error)
|
Error(err error)
|
||||||
Trace(start time.Time, args ...string)
|
Trace(start time.Time, args ...string)
|
||||||
|
@ -846,6 +874,39 @@ func (env *Shell) CursorPosition() (row, col int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (env *Shell) SystemInfo() (*SystemInfo, error) {
|
||||||
|
s := &SystemInfo{}
|
||||||
|
|
||||||
|
mem, err := env.Memory()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.Memory = *mem
|
||||||
|
|
||||||
|
loadStat, err := load.Avg()
|
||||||
|
if err == nil {
|
||||||
|
s.Load1 = loadStat.Load1
|
||||||
|
s.Load5 = loadStat.Load5
|
||||||
|
s.Load15 = loadStat.Load15
|
||||||
|
}
|
||||||
|
|
||||||
|
processorTimes, err := cpu.Percent(0, false)
|
||||||
|
if err == nil && len(processorTimes) > 0 {
|
||||||
|
s.Times = processorTimes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
processors, err := cpu.Info()
|
||||||
|
if err == nil {
|
||||||
|
s.CPU = processors
|
||||||
|
}
|
||||||
|
|
||||||
|
diskIO, err := disk.IOCounters()
|
||||||
|
if err == nil {
|
||||||
|
s.Disks = diskIO
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
func IsPathSeparator(env Environment, c uint8) bool {
|
func IsPathSeparator(env Environment, c uint8) bool {
|
||||||
if c == '/' {
|
if c == '/' {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shirou/gopsutil/v3/host"
|
"github.com/shirou/gopsutil/v3/host"
|
||||||
|
mem "github.com/shirou/gopsutil/v3/mem"
|
||||||
terminal "github.com/wayneashleyberry/terminal-dimensions"
|
terminal "github.com/wayneashleyberry/terminal-dimensions"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
@ -139,3 +140,24 @@ func (env *Shell) Connection(connectionType ConnectionType) (*Connection, error)
|
||||||
}
|
}
|
||||||
return nil, &NotImplemented{}
|
return nil, &NotImplemented{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (env *Shell) Memory() (*Memory, error) {
|
||||||
|
m := &Memory{}
|
||||||
|
memStat, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
env.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m.PhysicalTotalMemory = memStat.Total
|
||||||
|
m.PhysicalAvailableMemory = memStat.Available
|
||||||
|
m.PhysicalFreeMemory = memStat.Free
|
||||||
|
m.PhysicalPercentUsed = memStat.UsedPercent
|
||||||
|
swapStat, err := mem.SwapMemory()
|
||||||
|
if err != nil {
|
||||||
|
env.Error(err)
|
||||||
|
}
|
||||||
|
m.SwapTotalMemory = swapStat.Total
|
||||||
|
m.SwapFreeMemory = swapStat.Free
|
||||||
|
m.SwapPercentUsed = swapStat.UsedPercent
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
|
@ -317,3 +317,36 @@ func (env *Shell) isWriteable(folder string) bool {
|
||||||
env.Debug("no write access")
|
env.Debug("no write access")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
globalMemoryStatusEx = kernel32.NewProc("GlobalMemoryStatusEx")
|
||||||
|
)
|
||||||
|
|
||||||
|
type memoryStatusEx struct {
|
||||||
|
Length uint32
|
||||||
|
MemoryLoad uint32
|
||||||
|
TotalPhys uint64
|
||||||
|
AvailPhys uint64
|
||||||
|
TotalPageFile uint64
|
||||||
|
AvailPageFile uint64
|
||||||
|
TotalVirtual uint64
|
||||||
|
AvailVirtual uint64
|
||||||
|
AvailExtendedVirtual uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env *Shell) Memory() (*Memory, error) {
|
||||||
|
var memStat memoryStatusEx
|
||||||
|
memStat.Length = uint32(unsafe.Sizeof(memStat))
|
||||||
|
r0, _, err := globalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memStat)))
|
||||||
|
if r0 == 0 {
|
||||||
|
env.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Memory{
|
||||||
|
PhysicalTotalMemory: memStat.TotalPhys,
|
||||||
|
PhysicalFreeMemory: memStat.AvailPhys,
|
||||||
|
PhysicalAvailableMemory: memStat.AvailPhys,
|
||||||
|
PhysicalPercentUsed: float64(memStat.MemoryLoad),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
@ -3,11 +3,6 @@ package segments
|
||||||
import (
|
import (
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/platform"
|
"github.com/jandedobbeleer/oh-my-posh/src/platform"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||||
|
|
||||||
cpu "github.com/shirou/gopsutil/v3/cpu"
|
|
||||||
disk "github.com/shirou/gopsutil/v3/disk"
|
|
||||||
load "github.com/shirou/gopsutil/v3/load"
|
|
||||||
mem "github.com/shirou/gopsutil/v3/mem"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SystemInfo struct {
|
type SystemInfo struct {
|
||||||
|
@ -15,23 +10,8 @@ type SystemInfo struct {
|
||||||
env platform.Environment
|
env platform.Environment
|
||||||
|
|
||||||
Precision int
|
Precision int
|
||||||
// mem
|
|
||||||
PhysicalTotalMemory uint64
|
platform.SystemInfo
|
||||||
PhysicalAvailableMemory uint64
|
|
||||||
PhysicalFreeMemory uint64
|
|
||||||
PhysicalPercentUsed float64
|
|
||||||
SwapTotalMemory uint64
|
|
||||||
SwapFreeMemory uint64
|
|
||||||
SwapPercentUsed float64
|
|
||||||
// cpu
|
|
||||||
Times float64
|
|
||||||
CPU []cpu.InfoStat
|
|
||||||
// load
|
|
||||||
Load1 float64
|
|
||||||
Load5 float64
|
|
||||||
Load15 float64
|
|
||||||
// disk
|
|
||||||
Disks map[string]disk.IOCountersStat
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -54,40 +34,9 @@ func (s *SystemInfo) Init(props properties.Properties, env platform.Environment)
|
||||||
s.props = props
|
s.props = props
|
||||||
s.env = env
|
s.env = env
|
||||||
s.Precision = s.props.GetInt(Precision, 2)
|
s.Precision = s.props.GetInt(Precision, 2)
|
||||||
// mem
|
sysInfo, err := env.SystemInfo()
|
||||||
memStat, err := mem.VirtualMemory()
|
if err != nil {
|
||||||
if err == nil {
|
return
|
||||||
s.PhysicalTotalMemory = memStat.Total
|
|
||||||
s.PhysicalAvailableMemory = memStat.Available
|
|
||||||
s.PhysicalFreeMemory = memStat.Free
|
|
||||||
s.PhysicalPercentUsed = memStat.UsedPercent
|
|
||||||
}
|
|
||||||
swapStat, err := mem.SwapMemory()
|
|
||||||
if err == nil {
|
|
||||||
s.SwapTotalMemory = swapStat.Total
|
|
||||||
s.SwapFreeMemory = swapStat.Free
|
|
||||||
s.SwapPercentUsed = swapStat.UsedPercent
|
|
||||||
}
|
|
||||||
// load
|
|
||||||
loadStat, err := load.Avg()
|
|
||||||
if err == nil {
|
|
||||||
s.Load1 = loadStat.Load1
|
|
||||||
s.Load5 = loadStat.Load5
|
|
||||||
s.Load15 = loadStat.Load15
|
|
||||||
}
|
|
||||||
// times
|
|
||||||
processorTimes, err := cpu.Percent(0, false)
|
|
||||||
if err == nil && len(processorTimes) > 0 {
|
|
||||||
s.Times = processorTimes[0]
|
|
||||||
}
|
|
||||||
// cpu
|
|
||||||
processors, err := cpu.Info()
|
|
||||||
if err == nil {
|
|
||||||
s.CPU = processors
|
|
||||||
}
|
|
||||||
// disk
|
|
||||||
diskIO, err := disk.IOCounters()
|
|
||||||
if err == nil {
|
|
||||||
s.Disks = diskIO
|
|
||||||
}
|
}
|
||||||
|
s.SystemInfo = *sysInfo
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package segments
|
package segments
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/mock"
|
"github.com/jandedobbeleer/oh-my-posh/src/mock"
|
||||||
|
"github.com/jandedobbeleer/oh-my-posh/src/platform"
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
"github.com/jandedobbeleer/oh-my-posh/src/properties"
|
||||||
|
|
||||||
"github.com/shirou/gopsutil/v3/cpu"
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
@ -15,53 +17,85 @@ func TestSysInfo(t *testing.T) {
|
||||||
Case string
|
Case string
|
||||||
ExpectedString string
|
ExpectedString string
|
||||||
ExpectDisabled bool
|
ExpectDisabled bool
|
||||||
SysInfo SystemInfo
|
SysInfo platform.SystemInfo
|
||||||
Precision int
|
Precision int
|
||||||
Template string
|
Template string
|
||||||
|
Error error
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
Case: "Error",
|
||||||
|
ExpectDisabled: true,
|
||||||
|
Error: errors.New("error"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Case: "physical mem",
|
Case: "physical mem",
|
||||||
ExpectedString: "50",
|
ExpectedString: "50",
|
||||||
SysInfo: SystemInfo{PhysicalPercentUsed: 50},
|
SysInfo: platform.SystemInfo{
|
||||||
Template: "{{ round .PhysicalPercentUsed .Precision }}",
|
Memory: platform.Memory{
|
||||||
|
PhysicalPercentUsed: 50,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Template: "{{ round .PhysicalPercentUsed .Precision }}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "physical mem 2 digits",
|
Case: "physical mem 2 digits",
|
||||||
ExpectedString: "60.51",
|
ExpectedString: "60.51",
|
||||||
SysInfo: SystemInfo{Precision: 2, PhysicalPercentUsed: 60.51},
|
SysInfo: platform.SystemInfo{
|
||||||
Template: "{{ round .PhysicalPercentUsed .Precision }}",
|
Memory: platform.Memory{
|
||||||
|
PhysicalPercentUsed: 60.51,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Precision: 2,
|
||||||
|
Template: "{{ round .PhysicalPercentUsed .Precision }}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "physical meme rounded",
|
Case: "physical meme rounded",
|
||||||
ExpectedString: "61",
|
ExpectedString: "61",
|
||||||
SysInfo: SystemInfo{Precision: 0, PhysicalPercentUsed: 61},
|
SysInfo: platform.SystemInfo{
|
||||||
Template: "{{ round .PhysicalPercentUsed .Precision }}",
|
Memory: platform.Memory{
|
||||||
|
PhysicalPercentUsed: 61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Template: "{{ round .PhysicalPercentUsed .Precision }}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "load",
|
Case: "load",
|
||||||
ExpectedString: "0.22 0.12 0",
|
ExpectedString: "0.22 0.12 0",
|
||||||
|
Precision: 2,
|
||||||
Template: "{{ round .Load1 .Precision }} {{round .Load5 .Precision }} {{round .Load15 .Precision }}",
|
Template: "{{ round .Load1 .Precision }} {{round .Load5 .Precision }} {{round .Load15 .Precision }}",
|
||||||
SysInfo: SystemInfo{Precision: 2, Load1: 0.22, Load5: 0.12, Load15: 0}},
|
SysInfo: platform.SystemInfo{Load1: 0.22, Load5: 0.12, Load15: 0},
|
||||||
{Case: "not enabled", ExpectDisabled: true, SysInfo: SystemInfo{PhysicalPercentUsed: 0, SwapPercentUsed: 0}},
|
},
|
||||||
|
{
|
||||||
|
Case: "not enabled",
|
||||||
|
ExpectDisabled: true,
|
||||||
|
SysInfo: platform.SystemInfo{
|
||||||
|
Memory: platform.Memory{
|
||||||
|
PhysicalPercentUsed: 0,
|
||||||
|
SwapPercentUsed: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Case: "2 physical cpus",
|
Case: "2 physical cpus",
|
||||||
ExpectedString: "1200 1200",
|
ExpectedString: "1200 1200",
|
||||||
Template: "{{range $cpu := .CPU}}{{round $cpu.Mhz 2 }} {{end}}",
|
Template: "{{range $cpu := .CPU}}{{round $cpu.Mhz 2 }} {{end}}",
|
||||||
SysInfo: SystemInfo{CPU: []cpu.InfoStat{{Mhz: 1200}, {Mhz: 1200}}},
|
SysInfo: platform.SystemInfo{CPU: []cpu.InfoStat{{Mhz: 1200}, {Mhz: 1200}}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := new(mock.MockedEnvironment)
|
env := new(mock.MockedEnvironment)
|
||||||
tc.SysInfo.env = env
|
env.On("SystemInfo").Return(&tc.SysInfo, tc.Error)
|
||||||
tc.SysInfo.props = properties.Map{
|
sysInfo := &SystemInfo{}
|
||||||
|
props := properties.Map{
|
||||||
Precision: tc.Precision,
|
Precision: tc.Precision,
|
||||||
}
|
}
|
||||||
enabled := tc.SysInfo.Enabled()
|
sysInfo.Init(props, env)
|
||||||
|
enabled := sysInfo.Enabled()
|
||||||
if tc.ExpectDisabled {
|
if tc.ExpectDisabled {
|
||||||
assert.Equal(t, false, enabled, tc.Case)
|
assert.Equal(t, false, enabled, tc.Case)
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, tc.SysInfo), tc.Case)
|
assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, sysInfo), tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue