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 }