From a29a8f1dd9aa903071b9f17a0c7632b2128f0bf5 Mon Sep 17 00:00:00 2001 From: CapCreeperGR Date: Tue, 14 May 2024 10:03:18 +0300 Subject: [PATCH] CPU, GPU and memory information have been converted to Golang functions --- Utils.go | 207 +++++++++++++++++++++++++++++++ config/fetch_script.sh | 8 +- config/fetch_script_functions.sh | 16 --- go.mod | 17 ++- go.sum | 31 +++++ main.go | 128 ++----------------- 6 files changed, 268 insertions(+), 139 deletions(-) create mode 100644 Utils.go diff --git a/Utils.go b/Utils.go new file mode 100644 index 0000000..e2a1ca5 --- /dev/null +++ b/Utils.go @@ -0,0 +1,207 @@ +package main + +import ( + "bufio" + "github.com/jackmordaunt/ghw" + "os" + "path" + "regexp" + "strconv" + "strings" +) + +type DistroInfo struct { + ID string + LongName string + ShortName string +} + +func getDistroInfo() DistroInfo { + distroID := "" + var releaseMap = make(map[string]string) + if _, err := os.Stat("/etc/os-release"); err == nil { + releaseMap, err = readKeyValueFile("/etc/os-release") + if err != nil { + return DistroInfo{ + ID: "unknown", + LongName: "Unknown", + ShortName: "Unknown", + } + } + if value, ok := releaseMap["ID"]; ok { + distroID = value + } + } + + switch distroID { + default: + if id, ok := releaseMap["ID"]; ok { + if longName, ok := releaseMap["PRETTY_NAME"]; ok { + if shortName, ok := releaseMap["NAME"]; ok { + return DistroInfo{ + ID: id, + LongName: longName, + ShortName: shortName, + } + } + } + } + return DistroInfo{ + ID: "unknown", + LongName: "Unknown", + ShortName: "Unknown", + } + } +} + +func getDistroAsciiArt() string { + defaultAscii := + ` .--. + |o_o | + |:_/ | + // \ \ + (| | ) +/'\_ _/'\ +\___)=(___/ ` + var id string + if config.Ascii == "auto" { + id = getDistroInfo().ID + } else { + id = config.Ascii + } + userConfDir, err := os.UserConfigDir() + if err != nil { + if _, err := os.Stat(path.Join("/etc/stormfetch/ascii/", id)); err == nil { + bytes, err := os.ReadFile(path.Join("/etc/stormfetch/ascii/", id)) + if err != nil { + return defaultAscii + } + return string(bytes) + } else { + return defaultAscii + } + } + if _, err := os.Stat(path.Join(userConfDir, "stormfetch/ascii/", id)); err == nil { + bytes, err := os.ReadFile(path.Join(userConfDir, "stormfetch/ascii/", id)) + if err != nil { + return defaultAscii + } + return string(bytes) + } else if _, err := os.Stat(path.Join("/etc/stormfetch/ascii/", id)); err == nil { + bytes, err := os.ReadFile(path.Join("/etc/stormfetch/ascii/", id)) + if err != nil { + return defaultAscii + } + return string(bytes) + } else { + return defaultAscii + } +} + +func getCPUName() string { + cpu, err := ghw.CPU() + if err != nil { + return "" + } + return cpu.Processors[0].Model +} + +func getCPUThreads() int { + cpu, err := ghw.CPU() + if err != nil { + return 0 + } + return int(cpu.TotalThreads) +} + +func getGPUName() string { + null, _ := os.Open(os.DevNull) + serr := os.Stderr + os.Stderr = null + gpu, err := ghw.GPU() + defer null.Close() + os.Stderr = serr + if err != nil { + return "" + } + if len(gpu.GraphicsCards) == 0 { + return "" + } + return gpu.GraphicsCards[0].DeviceInfo.Product.Name +} + +type Memory struct { + MemTotal int + MemFree int + MemAvailable int +} + +func GetMemoryInfo() Memory { + toInt := func(raw string) int { + if raw == "" { + return 0 + } + res, err := strconv.Atoi(raw) + if err != nil { + panic(err) + } + return res + } + + parseLine := func(raw string) (key string, value int) { + text := strings.ReplaceAll(raw[:len(raw)-2], " ", "") + keyValue := strings.Split(text, ":") + return keyValue[0], toInt(keyValue[1]) + } + + file, err := os.Open("/proc/meminfo") + if err != nil { + panic(err) + } + defer file.Close() + bufio.NewScanner(file) + scanner := bufio.NewScanner(file) + res := Memory{} + for scanner.Scan() { + key, value := parseLine(scanner.Text()) + switch key { + case "MemTotal": + res.MemTotal = value / 1024 + case "MemFree": + res.MemFree = value / 1024 + case "MemAvailable": + res.MemAvailable = value / 1024 + } + } + return res +} + +func stripAnsii(str string) string { + const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" + var re = regexp.MustCompile(ansi) + return re.ReplaceAllString(str, "") +} + +func readKeyValueFile(filepath string) (map[string]string, error) { + ret := make(map[string]string) + if _, err := os.Stat(filepath); err != nil { + return nil, err + } + bytes, err := os.ReadFile(filepath) + if err != nil { + return nil, err + } + str := string(bytes) + lines := strings.Split(str, "\n") + for _, line := range lines { + if len(strings.Split(line, "=")) >= 2 { + key := strings.SplitN(line, "=", 2)[0] + value := strings.SplitN(line, "=", 2)[1] + if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") { + value = value[1 : len(value)-1] + } + ret[key] = value + } + } + return ret, nil +} diff --git a/config/fetch_script.sh b/config/fetch_script.sh index 84e8472..f88f231 100644 --- a/config/fetch_script.sh +++ b/config/fetch_script.sh @@ -5,11 +5,11 @@ echo -e "${C3}Hostname: ${C4}$(cat /etc/hostname)" echo -e "${C3}Kernel: ${C4}$(uname -s) $(uname -r)" echo -e "${C3}Packages: ${C4}$(get_packages)" echo -e "${C3}Shell: ${C4}$(get_shell)" -echo -e "${C3}CPU: ${C4}$(get_cpu_name) ($(nproc) threads)" -if command_exists lshw; then - echo -e "${C3}GPU: ${C4}$(lshw -class display 2> /dev/null | grep 'product' | cut -d":" -f2 | xargs)" +echo -e "${C3}CPU: ${C4}${CPU_MODEL} (${CPU_THREADS} threads)" +if [ ! -z "$GPU_MODEL" ]; then + echo -e "${C3}GPU: ${C4}${GPU_MODEL})" fi -echo -e "${C3}Memory: ${C4}$(get_used_mem) MiB / $(get_total_mem) MiB" +echo -e "${C3}Memory: ${C4}${MEM_USED} MiB / ${MEM_TOTAL} MiB" if xhost >& /dev/null ; then if get_de_wm &> /dev/null; then echo -e "${C3}DE/WM: ${C4}$(get_de_wm)" diff --git a/config/fetch_script_functions.sh b/config/fetch_script_functions.sh index f8a00c9..7fa13e8 100644 --- a/config/fetch_script_functions.sh +++ b/config/fetch_script_functions.sh @@ -34,22 +34,6 @@ get_shell() { esac } -get_cpu_name() { - grep -m1 "model name" /proc/cpuinfo | cut -d: -f2 | xargs -} - -get_total_mem() { - free --mebi -t | grep 'Total' | tr -s ' ' | cut -d" " -f2 -} - -get_free_mem() { - free --mebi -t | grep 'Total' | tr -s ' ' | cut -d" " -f4 -} - -get_used_mem() { - free --mebi -t | grep 'Total' | tr -s ' ' | cut -d" " -f3 -} - get_de_wm() { if ps -e | grep "plasmashell" &> /dev/null ; then echo "KDE Plasma $(plasmashell --version | awk '{print $2}')" diff --git a/go.mod b/go.mod index c7a8667..84f8e46 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,19 @@ module stormfetch go 1.22 -require gopkg.in/yaml.v3 v3.0.1 // indirect +require ( + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/jackmordaunt/ghw v1.0.4 // indirect + github.com/jackmordaunt/pcidb v1.0.1 // indirect + github.com/jackmordaunt/wmi v1.2.4 // indirect + github.com/jaypipes/ghw v0.12.0 // indirect + github.com/jaypipes/pcidb v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + golang.org/x/sys v0.3.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + howett.net/plist v1.0.0 // indirect +) diff --git a/go.sum b/go.sum index 4bc0337..03d0abd 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,34 @@ +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/jackmordaunt/ghw v1.0.4 h1:as+COFuPuXaNQC3WqzoHS/E2JYWZU7gN8ompNTUxNxs= +github.com/jackmordaunt/ghw v1.0.4/go.mod h1:4dReYvJ36CoAzIxlEx8du25Qi/YqKYvEGE9QJoRXiK8= +github.com/jackmordaunt/pcidb v1.0.1 h1:uLLZa6kD5P39r2cwMyJJkxmuHfH9Wq19gYQEbYcB0Z4= +github.com/jackmordaunt/pcidb v1.0.1/go.mod h1:OMmhrZOZVu2hYXhBDZXddypxwKR/dp4DbIgzCkQDxdQ= +github.com/jackmordaunt/wmi v1.2.4 h1:/XyuMiKby0qXNQp1j0uU0JqTWLM0QGOVok1Hf5Yagtg= +github.com/jackmordaunt/wmi v1.2.4/go.mod h1:K/+FH4467Vk2fJXhYQTZzhctkCMMR7PwHqKbnizFySo= +github.com/jaypipes/ghw v0.11.0/go.mod h1:jeJGbkRB2lL3/gxYzNYzEDETV1ZJ56OKr+CSeSEym+g= +github.com/jaypipes/ghw v0.12.0 h1:xU2/MDJfWmBhJnujHY9qwXQLs3DBsf0/Xa9vECY0Tho= +github.com/jaypipes/ghw v0.12.0/go.mod h1:jeJGbkRB2lL3/gxYzNYzEDETV1ZJ56OKr+CSeSEym+g= +github.com/jaypipes/pcidb v1.0.0 h1:vtZIfkiCUE42oYbJS0TAq9XSfSmcsgo9IdxSm9qzYU8= +github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLRCuNDfk= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= +howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= diff --git a/main.go b/main.go index e45e9eb..1a5a058 100644 --- a/main.go +++ b/main.go @@ -31,12 +31,6 @@ type StormfetchConfig struct { DependencyWarning bool `yaml:"dependency_warning"` } -type DistroInfo struct { - ID string - LongName string - ShortName string -} - func main() { readConfig() } @@ -147,6 +141,16 @@ func readConfig() { } cmd.Env = append(cmd.Env, "DISTRO_LONG_NAME="+getDistroInfo().LongName) cmd.Env = append(cmd.Env, "DISTRO_SHORT_NAME="+getDistroInfo().ShortName) + cmd.Env = append(cmd.Env, "CPU_MODEL="+getCPUName()) + cmd.Env = append(cmd.Env, "CPU_THREADS="+strconv.Itoa(getCPUThreads())) + memory := GetMemoryInfo() + cmd.Env = append(cmd.Env, "MEM_TOTAL="+strconv.Itoa(memory.MemTotal)) + cmd.Env = append(cmd.Env, "MEM_USED="+strconv.Itoa(memory.MemTotal-memory.MemAvailable)) + cmd.Env = append(cmd.Env, "MEM_FREE="+strconv.Itoa(memory.MemAvailable)) + + if getGPUName() != "" { + cmd.Env = append(cmd.Env, "GPU_MODEL="+getGPUName()) + } out, err := cmd.Output() if err != nil { log.Fatal(err) @@ -181,115 +185,3 @@ func readConfig() { } fmt.Println(final) } - -func readKeyValueFile(filepath string) (map[string]string, error) { - ret := make(map[string]string) - if _, err := os.Stat(filepath); err != nil { - return nil, err - } - bytes, err := os.ReadFile(filepath) - if err != nil { - return nil, err - } - str := string(bytes) - lines := strings.Split(str, "\n") - for _, line := range lines { - if len(strings.Split(line, "=")) >= 2 { - key := strings.SplitN(line, "=", 2)[0] - value := strings.SplitN(line, "=", 2)[1] - if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") { - value = value[1 : len(value)-1] - } - ret[key] = value - } - } - return ret, nil -} - -func getDistroInfo() DistroInfo { - distroID := "" - var releaseMap = make(map[string]string) - if _, err := os.Stat("/etc/os-release"); err == nil { - releaseMap, err = readKeyValueFile("/etc/os-release") - if err != nil { - return DistroInfo{ - ID: "unknown", - LongName: "Unknown", - ShortName: "Unknown", - } - } - if value, ok := releaseMap["ID"]; ok { - distroID = value - } - } - - switch distroID { - default: - if id, ok := releaseMap["ID"]; ok { - if longName, ok := releaseMap["PRETTY_NAME"]; ok { - if shortName, ok := releaseMap["NAME"]; ok { - return DistroInfo{ - ID: id, - LongName: longName, - ShortName: shortName, - } - } - } - } - return DistroInfo{ - ID: "unknown", - LongName: "Unknown", - ShortName: "Unknown", - } - } -} - -func getDistroAsciiArt() string { - defaultAscii := - ` .--. - |o_o | - |:_/ | - // \ \ - (| | ) -/'\_ _/'\ -\___)=(___/ ` - var id string - if config.Ascii == "auto" { - id = getDistroInfo().ID - } else { - id = config.Ascii - } - userConfDir, err := os.UserConfigDir() - if err != nil { - if _, err := os.Stat(path.Join("/etc/stormfetch/ascii/", id)); err == nil { - bytes, err := os.ReadFile(path.Join("/etc/stormfetch/ascii/", id)) - if err != nil { - return defaultAscii - } - return string(bytes) - } else { - return defaultAscii - } - } - if _, err := os.Stat(path.Join(userConfDir, "stormfetch/ascii/", id)); err == nil { - bytes, err := os.ReadFile(path.Join(userConfDir, "stormfetch/ascii/", id)) - if err != nil { - return defaultAscii - } - return string(bytes) - } else if _, err := os.Stat(path.Join("/etc/stormfetch/ascii/", id)); err == nil { - bytes, err := os.ReadFile(path.Join("/etc/stormfetch/ascii/", id)) - if err != nil { - return defaultAscii - } - return string(bytes) - } else { - return defaultAscii - } -} - -func stripAnsii(str string) string { - const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" - var re = regexp.MustCompile(ansi) - return re.ReplaceAllString(str, "") -}