mirror of
https://github.com/EnumeratedDev/stormfetch.git
synced 2026-09-15 23:46:12 +00:00
Remove dependency on bash, switch to new module system and simplify code
This commit is contained in:
+11
-10
@@ -2,21 +2,22 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func setupColorMap(asciiArt string) map[string]string {
|
||||
colorMap := make(map[string]string)
|
||||
func setupColorMap(asciiArtHeader string) map[int]string {
|
||||
colorMap := make(map[int]string)
|
||||
colorMap[0] = "\033[0m"
|
||||
|
||||
// Read colors from ascii art
|
||||
if strings.HasPrefix(asciiArt, "#/") {
|
||||
firstLine := strings.Split(asciiArt, "\n")[0]
|
||||
ansiColors := strings.Split(strings.TrimPrefix(firstLine, "#/"), ";")
|
||||
// Return if header is empty
|
||||
if asciiArtHeader == "" {
|
||||
return colorMap
|
||||
}
|
||||
|
||||
for i, ansiColor := range ansiColors {
|
||||
colorMap["C"+strconv.Itoa(i+1)] = fmt.Sprintf("\033[38;5;%sm", ansiColor)
|
||||
}
|
||||
// Read colors from ascii art header
|
||||
ansiColors := strings.Split(strings.TrimPrefix(asciiArtHeader, "#/"), ";")
|
||||
for i, ansiColor := range ansiColors {
|
||||
colorMap[i+1] = fmt.Sprintf("\033[38;5;%sm", ansiColor)
|
||||
}
|
||||
|
||||
return colorMap
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type StormfetchConfig struct {
|
||||
Ascii string `yaml:"distro_ascii"`
|
||||
DistroName string `yaml:"distro_name"`
|
||||
Modules []stormfetchModuleConfig `yaml:"modules"`
|
||||
AnsiiColors []int `yaml:"ansii_colors"`
|
||||
ForceConfigAnsii bool `yaml:"force_config_ansii"`
|
||||
}
|
||||
|
||||
var config = StormfetchConfig{
|
||||
Ascii: "auto",
|
||||
Modules: make([]stormfetchModuleConfig, 0),
|
||||
}
|
||||
|
||||
func readConfig() {
|
||||
// Get home directory
|
||||
userConfigDir, _ := os.UserConfigDir()
|
||||
|
||||
// Find valid config directory
|
||||
if _, err := os.Stat(path.Join(userConfigDir, "stormfetch/config.yaml")); err == nil {
|
||||
configPath = path.Join(userConfigDir, "stormfetch/config.yaml")
|
||||
} else if _, err := os.Stat(path.Join(systemConfigDir, "stormfetch/config.yaml")); err == nil {
|
||||
configPath = path.Join(systemConfigDir, "stormfetch/config.yaml")
|
||||
} else {
|
||||
log.Fatalf("Config file not found: %s", err.Error())
|
||||
}
|
||||
|
||||
// Parse config
|
||||
bytes, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = yaml.Unmarshal(bytes, &config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
+20
-8
@@ -1,15 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-gl/glfw/v3.3/glfw"
|
||||
"github.com/jackmordaunt/ghw"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gl/glfw/v3.3/glfw"
|
||||
"github.com/jackmordaunt/ghw"
|
||||
)
|
||||
|
||||
type Monitor struct {
|
||||
Width int
|
||||
Height int
|
||||
RefreshRate int
|
||||
}
|
||||
|
||||
func GetCPUModel() string {
|
||||
cpu, err := ghw.CPU()
|
||||
if err != nil {
|
||||
@@ -29,7 +35,7 @@ func GetCPUThreads() int {
|
||||
return int(cpu.TotalThreads)
|
||||
}
|
||||
|
||||
func GetGPUModels() (ret []string) {
|
||||
func GetGPUModels(hiddenGPUS []int) (ret []string) {
|
||||
cmd := exec.Command("sh", "-c", "lspci -v -m | grep 'VGA' -A6 | grep '^Device:'")
|
||||
bytes, err := cmd.Output()
|
||||
if err != nil {
|
||||
@@ -37,7 +43,7 @@ func GetGPUModels() (ret []string) {
|
||||
}
|
||||
|
||||
for i, gpu := range strings.Split(string(bytes), "\n") {
|
||||
if slices.Contains(config.HiddenGPUS, i+1) {
|
||||
if slices.Contains(hiddenGPUS, i+1) {
|
||||
continue
|
||||
}
|
||||
if gpu == "" {
|
||||
@@ -58,16 +64,22 @@ func GetMotherboardModel() string {
|
||||
return strings.TrimSpace(string(bytes))
|
||||
}
|
||||
|
||||
func GetMonitorResolution() []string {
|
||||
var monitors []string
|
||||
func GetMonitors() []Monitor {
|
||||
var monitors []Monitor
|
||||
if GetDisplayProtocol() != "" {
|
||||
err := glfw.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, monitor := range glfw.GetMonitors() {
|
||||
mode := monitor.GetVideoMode()
|
||||
monitors = append(monitors, fmt.Sprintf("%dx%d %dHz", mode.Width, mode.Height, mode.RefreshRate))
|
||||
|
||||
monitors = append(monitors, Monitor{
|
||||
Width: mode.Width,
|
||||
Height: mode.Height,
|
||||
RefreshRate: mode.RefreshRate,
|
||||
})
|
||||
}
|
||||
defer glfw.Terminate()
|
||||
}
|
||||
|
||||
+96
-223
@@ -3,258 +3,131 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Build-time variables
|
||||
var systemConfigDir = "/etc/"
|
||||
|
||||
// Flag variables
|
||||
var ShowModuleTimeTaken = false
|
||||
|
||||
var configPath = ""
|
||||
var fetchScriptPath = ""
|
||||
|
||||
var TimeTaken = false
|
||||
|
||||
var config = StormfetchConfig{
|
||||
Ascii: "auto",
|
||||
FetchScript: "auto",
|
||||
ShowFSType: false,
|
||||
HiddenPartitions: make([]string, 0),
|
||||
HiddenGPUS: make([]int, 0),
|
||||
}
|
||||
|
||||
type StormfetchConfig struct {
|
||||
Ascii string `yaml:"distro_ascii"`
|
||||
DistroName string `yaml:"distro_name"`
|
||||
FetchScript string `yaml:"fetch_script"`
|
||||
AnsiiColors []int `yaml:"ansii_colors"`
|
||||
ForceConfigAnsii bool `yaml:"force_config_ansii"`
|
||||
ShowFSType bool `yaml:"show_fs_type"`
|
||||
HiddenPartitions []string `yaml:"hidden_partitions"`
|
||||
HiddenFilesystems []string `yaml:"hidden_filesystems"`
|
||||
HiddenGPUS []int `yaml:"hidden_gpus"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
readConfig()
|
||||
readFlags()
|
||||
runStormfetch()
|
||||
parseFlags()
|
||||
initializeModuleMap()
|
||||
run()
|
||||
}
|
||||
|
||||
func readConfig() {
|
||||
// Get home directory
|
||||
userConfigDir, _ := os.UserConfigDir()
|
||||
// Find valid config directory
|
||||
if _, err := os.Stat(path.Join(userConfigDir, "stormfetch/config.yaml")); err == nil {
|
||||
configPath = path.Join(userConfigDir, "stormfetch/config.yaml")
|
||||
} else if _, err := os.Stat(path.Join(systemConfigDir, "stormfetch/config.yaml")); err == nil {
|
||||
configPath = path.Join(systemConfigDir, "stormfetch/config.yaml")
|
||||
} else {
|
||||
log.Fatalf("Config file not found: %s", err.Error())
|
||||
}
|
||||
// Parse config
|
||||
bytes, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = yaml.Unmarshal(bytes, &config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if config.FetchScript == "" {
|
||||
log.Fatalf("Fetch script path is empty")
|
||||
} else if config.FetchScript != "auto" {
|
||||
stat, err := os.Stat(config.FetchScript)
|
||||
if err != nil {
|
||||
log.Fatalf("Fetch script file not found: %s", err.Error())
|
||||
} else if stat.IsDir() {
|
||||
log.Fatalf("Fetch script path points to a directory")
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path.Join(userConfigDir, "stormfetch/fetch_script.sh")); err == nil {
|
||||
fetchScriptPath = path.Join(userConfigDir, "stormfetch/fetch_script.sh")
|
||||
} else if _, err := os.Stat(path.Join(systemConfigDir, "stormfetch/fetch_script.sh")); err == nil {
|
||||
fetchScriptPath = path.Join(systemConfigDir, "stormfetch/fetch_script.sh")
|
||||
} else {
|
||||
log.Fatalf("Fetch script file not found: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func readFlags() {
|
||||
func parseFlags() {
|
||||
flag.StringVar(&config.Ascii, "ascii", config.Ascii, "Set distro ascii")
|
||||
flag.StringVar(&config.DistroName, "distro-name", config.DistroName, "Set distro name")
|
||||
flag.BoolVar(&TimeTaken, "time-taken", false, "Show time taken for fetched information")
|
||||
flag.BoolVar(&ShowModuleTimeTaken, "time-taken", false, "Show time taken to execute each module")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func SetupFetchEnv(showTimeTaken bool) []string {
|
||||
var env = make(map[string]string)
|
||||
setVariable := func(key string, setter func() string) {
|
||||
start := time.Now().UnixMilli()
|
||||
env[key] = setter()
|
||||
end := time.Now().UnixMilli()
|
||||
if showTimeTaken {
|
||||
fmt.Printf("Setting '%s' took %d milliseconds\n", key, end-start)
|
||||
}
|
||||
}
|
||||
setVariable("PACKAGES", func() string { return GetInstalledPackages() })
|
||||
setVariable("DISTRO_LONG_NAME", func() string { return GetDistroInfo().LongName })
|
||||
setVariable("DISTRO_SHORT_NAME", func() string { return GetDistroInfo().ShortName })
|
||||
setVariable("CPU_MODEL", func() string { return GetCPUModel() })
|
||||
setVariable("MOTHERBOARD", func() string { return GetMotherboardModel() })
|
||||
setVariable("CPU_THREADS", func() string { return strconv.Itoa(GetCPUThreads()) })
|
||||
start := time.Now().UnixMilli()
|
||||
memory := GetMemoryInfo()
|
||||
end := time.Now().UnixMilli()
|
||||
if showTimeTaken {
|
||||
fmt.Printf("Setting '%s' took %d milliseconds\n", "MEM_*", end-start)
|
||||
}
|
||||
if memory != nil {
|
||||
env["MEM_TOTAL"] = strconv.Itoa(memory.MemTotal)
|
||||
env["MEM_USED"] = strconv.Itoa(memory.MemTotal - memory.MemAvailable)
|
||||
env["MEM_FREE"] = strconv.Itoa(memory.MemAvailable)
|
||||
}
|
||||
start = time.Now().UnixMilli()
|
||||
partitions := GetMountedPartitions(config.HiddenPartitions, config.HiddenFilesystems)
|
||||
end = time.Now().UnixMilli()
|
||||
if showTimeTaken {
|
||||
fmt.Printf("Setting '%s' took %d milliseconds\n", "PARTITION_*", end-start)
|
||||
}
|
||||
if len(partitions) != 0 {
|
||||
env["MOUNTED_PARTITIONS"] = strconv.Itoa(len(partitions))
|
||||
for i, part := range partitions {
|
||||
env["PARTITION"+strconv.Itoa(i+1)+"_DEVICE"] = part.Device
|
||||
env["PARTITION"+strconv.Itoa(i+1)+"_MOUNTPOINT"] = part.MountPoint
|
||||
if part.Label != "" {
|
||||
env["PARTITION"+strconv.Itoa(i+1)+"_LABEL"] = part.Label
|
||||
}
|
||||
if part.FileystemType != "" && config.ShowFSType {
|
||||
env["PARTITION"+strconv.Itoa(i+1)+"_TYPE"] = part.FileystemType
|
||||
}
|
||||
env["PARTITION"+strconv.Itoa(i+1)+"_TOTAL_SIZE"] = FormatBytes(part.TotalSize)
|
||||
env["PARTITION"+strconv.Itoa(i+1)+"_USED_SIZE"] = FormatBytes(part.UsedSize)
|
||||
env["PARTITION"+strconv.Itoa(i+1)+"_FREE_SIZE"] = FormatBytes(part.FreeSize)
|
||||
}
|
||||
}
|
||||
setVariable("DE_WM", func() string { return GetDEWM() })
|
||||
setVariable("USER_SHELL", func() string { return GetShell() })
|
||||
setVariable("DISPLAY_PROTOCOL", func() string { return GetDisplayProtocol() })
|
||||
setVariable("LIBC", func() string { return GetLibc() })
|
||||
setVariable("INIT_SYSTEM", func() string { return GetInitSystem() })
|
||||
setVariable("LOCAL_IPV4", func() string { return GetLocalIP() })
|
||||
start = time.Now().UnixMilli()
|
||||
monitors := GetMonitorResolution()
|
||||
end = time.Now().UnixMilli()
|
||||
if showTimeTaken {
|
||||
fmt.Printf("Setting '%s' took %d milliseconds\n", "MONITOR_*", end-start)
|
||||
}
|
||||
if len(monitors) != 0 {
|
||||
env["CONNECTED_MONITORS"] = strconv.Itoa(len(monitors))
|
||||
for i, monitor := range monitors {
|
||||
env["MONITOR"+strconv.Itoa(i+1)] = monitor
|
||||
}
|
||||
}
|
||||
start = time.Now().UnixMilli()
|
||||
gpus := GetGPUModels()
|
||||
end = time.Now().UnixMilli()
|
||||
if showTimeTaken {
|
||||
fmt.Printf("Setting '%s' took %d milliseconds\n", "GPU_*", end-start)
|
||||
}
|
||||
if len(gpus) != 0 {
|
||||
env["CONNECTED_GPUS"] = strconv.Itoa(len(gpus))
|
||||
for i, gpu := range gpus {
|
||||
if gpu == "" {
|
||||
continue
|
||||
}
|
||||
env["GPU"+strconv.Itoa(i+1)] = gpu
|
||||
}
|
||||
}
|
||||
|
||||
var ret = make([]string, len(env))
|
||||
i := 0
|
||||
for key, value := range env {
|
||||
ret[i] = fmt.Sprintf("%s=%s", key, value)
|
||||
i++
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func runStormfetch() {
|
||||
// Fetch ascii art
|
||||
func run() {
|
||||
// Fetch ascii art and remove header
|
||||
asciiArt := GetDistroAsciiArt()
|
||||
|
||||
// Setup color map
|
||||
colorMap := setupColorMap(asciiArt)
|
||||
if len(colorMap) > 0 {
|
||||
asciiArt = os.Expand(asciiArt, func(s string) string {
|
||||
return colorMap[s]
|
||||
})
|
||||
|
||||
asciiArtHeader := ""
|
||||
if strings.HasPrefix(asciiArt, "#/") {
|
||||
asciiArtHeader = strings.SplitN(asciiArt, "\n", 2)[0]
|
||||
asciiArt = strings.SplitN(asciiArt, "\n", 2)[1]
|
||||
}
|
||||
asciiArtNoColor := asciiArt
|
||||
|
||||
asciiSplit := strings.Split(asciiArt, "\n")
|
||||
asciiNoColor := StripAnsii(asciiArt)
|
||||
|
||||
// Execute fetch script
|
||||
cmd := exec.Command("/bin/bash", fetchScriptPath)
|
||||
cmd.Dir = path.Dir(fetchScriptPath)
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, SetupFetchEnv(TimeTaken)...)
|
||||
cmd.Env = append(cmd.Env, "C0=\033[0m")
|
||||
// Setup color map and replace colors in ascii art
|
||||
colorMap := setupColorMap(asciiArtHeader)
|
||||
for key, value := range colorMap {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
|
||||
asciiArt = strings.ReplaceAll(asciiArt, "%"+strconv.Itoa(key), value)
|
||||
asciiArtNoColor = strings.ReplaceAll(asciiArtNoColor, "%"+strconv.Itoa(key), "")
|
||||
}
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Fatalf("Error: Could not run fetch script: %s", err)
|
||||
|
||||
// Execute modules in order
|
||||
modulesText := make([]string, 0)
|
||||
for _, moduleConfig := range config.Modules {
|
||||
module, ok := Modules[moduleConfig.Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Set module config options
|
||||
if moduleConfig.Format != "" {
|
||||
module.Format = moduleConfig.Format
|
||||
}
|
||||
if moduleConfig.Data != nil {
|
||||
module.Data = moduleConfig.Data
|
||||
}
|
||||
|
||||
// Execute module
|
||||
start := time.Now().UnixMilli()
|
||||
text := module.Execute(module)
|
||||
end := time.Now().UnixMilli()
|
||||
|
||||
// Show time taken
|
||||
if ShowModuleTimeTaken {
|
||||
fmt.Printf("Module '%s' took %d milliseconds\n", module.Name, end-start)
|
||||
}
|
||||
|
||||
// Replace colors in returned string
|
||||
textNoColor := text
|
||||
for key, value := range colorMap {
|
||||
text = strings.ReplaceAll(text, "%"+strconv.Itoa(key), value)
|
||||
textNoColor = strings.ReplaceAll(textNoColor, "%"+strconv.Itoa(key), value)
|
||||
}
|
||||
|
||||
// Continue if text length is 0
|
||||
if len(textNoColor) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add text to slice
|
||||
for _, line := range strings.Split(strings.TrimSpace(text), "\n") {
|
||||
modulesText = append(modulesText, line)
|
||||
}
|
||||
}
|
||||
// Print Distro Information
|
||||
|
||||
// Get longest line in ascii art
|
||||
maxWidth := 0
|
||||
for _, line := range strings.Split(asciiNoColor, "\n") {
|
||||
for _, line := range strings.Split(asciiArtNoColor, "\n") {
|
||||
if len(line) > maxWidth {
|
||||
maxWidth = len(line)
|
||||
}
|
||||
}
|
||||
final := ""
|
||||
y := len(asciiSplit)
|
||||
if len(asciiSplit) < len(strings.Split(string(out), "\n")) {
|
||||
y = len(strings.Split(string(out), "\n"))
|
||||
|
||||
// Split ascii art into each lien
|
||||
asciiArtSplit := strings.Split(asciiArt, "\n")
|
||||
asciiArtNoColorSplit := strings.Split(asciiArtNoColor, "\n")
|
||||
|
||||
// Get amount of lines to print
|
||||
lineCount := max(len(asciiArtSplit), len(modulesText))
|
||||
|
||||
// Combine ascii art and module text
|
||||
final := strings.Builder{}
|
||||
for i := range lineCount {
|
||||
// Write ascii art
|
||||
currentLineLength := 0
|
||||
if i < len(asciiArtSplit) {
|
||||
final.WriteString(asciiArtSplit[i])
|
||||
currentLineLength += len(asciiArtNoColorSplit[i])
|
||||
}
|
||||
|
||||
// Write blank space between ascii art and module text
|
||||
for i := currentLineLength; i < maxWidth+3; i++ {
|
||||
final.WriteString(" ")
|
||||
}
|
||||
|
||||
// Write module text
|
||||
if i < len(modulesText) {
|
||||
final.WriteString(modulesText[i])
|
||||
}
|
||||
|
||||
final.WriteString("\n")
|
||||
}
|
||||
for lineIndex := 0; lineIndex < y; lineIndex++ {
|
||||
line := ""
|
||||
for i := 0; i < maxWidth+5; i++ {
|
||||
line = line + " "
|
||||
}
|
||||
lastAsciiColor := ""
|
||||
if lineIndex < len(asciiSplit) {
|
||||
line = asciiSplit[lineIndex]
|
||||
lineVisibleLength := len(strings.Split(asciiNoColor, "\n")[lineIndex])
|
||||
if lineIndex != 0 {
|
||||
r := regexp.MustCompile("\033[38;5;[0-9]+m")
|
||||
matches := r.FindAllString(asciiSplit[lineIndex-1], -1)
|
||||
if len(matches) != 0 {
|
||||
lastAsciiColor = r.FindAllString(asciiSplit[lineIndex-1], -1)[len(matches)-1]
|
||||
}
|
||||
}
|
||||
for i := lineVisibleLength; i < maxWidth+5; i++ {
|
||||
line = line + " "
|
||||
}
|
||||
asciiSplit[lineIndex] = lastAsciiColor + line
|
||||
}
|
||||
str := string(out)
|
||||
if lineIndex < len(strings.Split(str, "\n")) {
|
||||
line = line + colorMap["C0"] + strings.Split(str, "\n")[lineIndex]
|
||||
}
|
||||
final += lastAsciiColor + line + "\n"
|
||||
}
|
||||
final = strings.TrimRight(final, "\n\t ")
|
||||
fmt.Println(final + "\033[0m")
|
||||
|
||||
fmt.Println(strings.TrimRight(final.String(), "\n") + "\033[0m")
|
||||
}
|
||||
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Used to declare modules in config files
|
||||
type stormfetchModuleConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
Format string `yaml:"format"`
|
||||
Data map[string]any `yaml:"data"`
|
||||
}
|
||||
|
||||
type StormfetchModule struct {
|
||||
Execute func(StormfetchModule) string
|
||||
stormfetchModuleConfig
|
||||
}
|
||||
|
||||
var Modules map[string]StormfetchModule = make(map[string]StormfetchModule)
|
||||
|
||||
func (sm StormfetchModule) GetData(key string, defaultValue any) (any, bool) {
|
||||
if sm.Data == nil {
|
||||
return defaultValue, false
|
||||
}
|
||||
|
||||
data, ok := sm.Data[key]
|
||||
if !ok {
|
||||
return defaultValue, false
|
||||
}
|
||||
|
||||
if reflect.ValueOf(data).Kind() != reflect.ValueOf(defaultValue).Kind() {
|
||||
return defaultValue, false
|
||||
}
|
||||
|
||||
return data, true
|
||||
}
|
||||
|
||||
func RegisterModule(module StormfetchModule) bool {
|
||||
if _, ok := Modules[module.Name]; ok {
|
||||
return false
|
||||
}
|
||||
|
||||
Modules[module.Name] = module
|
||||
return true
|
||||
}
|
||||
|
||||
func initializeModuleMap() {
|
||||
// Distribution Module
|
||||
distributionModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "distribution", Format: "%3Distribution: %4$DISTRO_SHORT ($ARCH)"}, Execute: func(sm StormfetchModule) string {
|
||||
distroInfo := GetDistroInfo()
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "DISTRO_ID":
|
||||
return distroInfo.ID
|
||||
case "DISTRO_SHORT":
|
||||
return distroInfo.ShortName
|
||||
case "DISTRO_LONG":
|
||||
return distroInfo.LongName
|
||||
case "ARCH":
|
||||
return GetArch()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(distributionModule)
|
||||
|
||||
// Hostname module
|
||||
hostnameModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "hostname", Format: "%3Hostname: %4$HOSTNAME"}, Execute: func(sm StormfetchModule) string {
|
||||
hostname, _ := os.Hostname()
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "HOSTNAME":
|
||||
return hostname
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(hostnameModule)
|
||||
|
||||
// Kernel module
|
||||
kernelModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "kernel", Format: "%3Kernel: %4$KERNEL_NAME $KERNEL_RELEASE"}, Execute: func(sm StormfetchModule) string {
|
||||
kernelName, kernelRelease := GetKernel()
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "KERNEL_NAME":
|
||||
return kernelName
|
||||
case "KERNEL_RELEASE":
|
||||
return kernelRelease
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(kernelModule)
|
||||
|
||||
// Packages module
|
||||
packagesModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "packages", Format: "%3Packages: %4$PACKAGES"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "PACKAGES":
|
||||
return GetInstalledPackages()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(packagesModule)
|
||||
|
||||
// Shell module
|
||||
shellModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "shell", Format: "%3Shell: %4$SHELL"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "SHELL":
|
||||
return GetShell()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(shellModule)
|
||||
|
||||
// Init system module
|
||||
initSystemModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "init_system", Format: "%3Init: %4$INIT"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "INIT":
|
||||
return GetInitSystem()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(initSystemModule)
|
||||
|
||||
// Libc module
|
||||
libcModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "libc", Format: "%3Libc: %4$LIBC"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "LIBC":
|
||||
return GetLibc()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(libcModule)
|
||||
|
||||
// Motherboard module
|
||||
MotherboardModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "motherboard", Format: "%3Motherboard: %4$MOTHERBOARD"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "MOTHERBOARD":
|
||||
return GetMotherboardModel()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(MotherboardModule)
|
||||
|
||||
// Motherboard module
|
||||
cpuModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "cpu", Format: "%3CPU: %4$CPU_MODEL ($CPU_THREADS threads)"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "CPU_MODEL":
|
||||
return GetCPUModel()
|
||||
case "CPU_THREADS":
|
||||
return strconv.Itoa(GetCPUThreads())
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(cpuModule)
|
||||
|
||||
// GPUs module
|
||||
gpusModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "gpus", Format: "%3GPU: %4$GPU_MODEL"}, Execute: func(sm StormfetchModule) string {
|
||||
hiddenGPUsInterface, _ := sm.GetData("hidden_gpus", make([]any, 0))
|
||||
|
||||
// Convert interface slices to string slices
|
||||
hiddenGPUs := make([]int, 0)
|
||||
for _, value := range hiddenGPUsInterface.([]any) {
|
||||
hiddenGPUs = append(hiddenGPUs, value.(int))
|
||||
}
|
||||
|
||||
builder := strings.Builder{}
|
||||
gpus := GetGPUModels(hiddenGPUs)
|
||||
|
||||
for i, gpu := range gpus {
|
||||
expanded := os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "GPU_NUM":
|
||||
return strconv.Itoa(i + 1)
|
||||
case "GPU_MODEL":
|
||||
return gpu
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
|
||||
builder.WriteString(expanded + "\n")
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}}
|
||||
RegisterModule(gpusModule)
|
||||
|
||||
// Memory module
|
||||
memoryModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "memory", Format: "%3Memory: %4$MEM_USED MiB / $MEM_TOTAL MiB"}, Execute: func(sm StormfetchModule) string {
|
||||
memoryInfo := GetMemoryInfo()
|
||||
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "MEM_TOTAL":
|
||||
return strconv.Itoa(memoryInfo.MemTotal)
|
||||
case "MEM_AVAILABLE":
|
||||
return strconv.Itoa(memoryInfo.MemAvailable)
|
||||
case "MEM_FREE":
|
||||
return strconv.Itoa(memoryInfo.MemFree)
|
||||
case "MEM_USED":
|
||||
return strconv.Itoa(memoryInfo.MemTotal - memoryInfo.MemAvailable)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(memoryModule)
|
||||
|
||||
// Partitions module
|
||||
partitionsModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "partitions", Format: "%3Partition $PART_AUTONAME: %4$PART_USED / $PART_TOTAL"}, Execute: func(sm StormfetchModule) string {
|
||||
hiddenPartitionsInterface, _ := sm.GetData("hidden_partitions", make([]any, 0))
|
||||
hiddenFilesystemsInterface, _ := sm.GetData("hidden_filesystems", make([]any, 0))
|
||||
|
||||
// Convert interface slices to string slices
|
||||
hiddenPartitions := make([]string, 0)
|
||||
for _, value := range hiddenPartitionsInterface.([]any) {
|
||||
hiddenPartitions = append(hiddenPartitions, value.(string))
|
||||
}
|
||||
hiddenFilesystems := make([]string, 0)
|
||||
for _, value := range hiddenFilesystemsInterface.([]any) {
|
||||
hiddenFilesystems = append(hiddenFilesystems, value.(string))
|
||||
}
|
||||
|
||||
builder := strings.Builder{}
|
||||
partitions := GetMountedPartitions(hiddenPartitions, hiddenFilesystems)
|
||||
|
||||
for i, partition := range partitions {
|
||||
partitionAutoname := partition.Label
|
||||
if partitionAutoname == "" {
|
||||
partitionAutoname = partition.MountPoint
|
||||
}
|
||||
|
||||
expanded := os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "PART_NUM":
|
||||
return strconv.Itoa(i + 1)
|
||||
case "PART_FS":
|
||||
return partition.FileystemType
|
||||
case "PART_DEVICE":
|
||||
return partition.Device
|
||||
case "PART_AUTONAME":
|
||||
return partitionAutoname
|
||||
case "PART_LABEL":
|
||||
return partition.Label
|
||||
case "PART_MOUNTPOINT":
|
||||
return partition.MountPoint
|
||||
case "PART_FREE":
|
||||
return FormatBytes(partition.FreeSize)
|
||||
case "PART_USED":
|
||||
return FormatBytes(partition.UsedSize)
|
||||
case "PART_TOTAL":
|
||||
return FormatBytes(partition.TotalSize)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
|
||||
builder.WriteString(expanded + "\n")
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}}
|
||||
RegisterModule(partitionsModule)
|
||||
|
||||
// Local IP module
|
||||
localIpModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "local_ip", Format: "%3Local IP: %4$LOCAL_IP"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "LOCAL_IP":
|
||||
return GetLocalIP()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(localIpModule)
|
||||
|
||||
// DEWM module
|
||||
dewmModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "de_wm", Format: "%3DE/WM: %4$DE_WM ($DISPLAY_PROTOCOL)"}, Execute: func(sm StormfetchModule) string {
|
||||
return os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "DE_WM":
|
||||
return GetDEWM()
|
||||
case "DISPLAY_PROTOCOL":
|
||||
return GetDisplayProtocol()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
}}
|
||||
RegisterModule(dewmModule)
|
||||
|
||||
// Monitors module
|
||||
monitorsModule := StormfetchModule{stormfetchModuleConfig: stormfetchModuleConfig{Name: "monitors", Format: "%3Monitor: %4${MONITOR_WIDTH}x${MONITOR_HEIGHT} ${MONITOR_REFRESH_RATE}Hz"}, Execute: func(sm StormfetchModule) string {
|
||||
builder := strings.Builder{}
|
||||
monitors := GetMonitors()
|
||||
|
||||
for i, monitor := range monitors {
|
||||
expanded := os.Expand(sm.Format, func(s string) string {
|
||||
switch s {
|
||||
case "MONITOR_NUM":
|
||||
return strconv.Itoa(i + 1)
|
||||
case "MONITOR_WIDTH":
|
||||
return strconv.Itoa(monitor.Width)
|
||||
case "MONITOR_HEIGHT":
|
||||
return strconv.Itoa(monitor.Height)
|
||||
case "MONITOR_REFRESH_RATE":
|
||||
return strconv.Itoa(monitor.RefreshRate)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
})
|
||||
|
||||
builder.WriteString(expanded + "\n")
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}}
|
||||
RegisterModule(monitorsModule)
|
||||
}
|
||||
+1
-1
@@ -95,7 +95,7 @@ func GetMountedPartitions(hiddenPartitions, hiddenFilesystems []string) []partit
|
||||
|
||||
// Set partition label if available
|
||||
if value, ok := labels[p.Device]; ok {
|
||||
p.Label = value
|
||||
p.Label = strings.ReplaceAll(value, "\\x20", " ")
|
||||
}
|
||||
|
||||
// Get partition total, used and free space
|
||||
|
||||
+39
-1
@@ -5,6 +5,7 @@ import (
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/mitchellh/go-ps"
|
||||
)
|
||||
@@ -99,9 +100,46 @@ func GetDistroAsciiArt() string {
|
||||
}
|
||||
}
|
||||
|
||||
func GetArch() string {
|
||||
uname := syscall.Utsname{}
|
||||
err := syscall.Uname(&uname)
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
var byteString [65]byte
|
||||
var indexLength int
|
||||
for ; uname.Machine[indexLength] != 0; indexLength++ {
|
||||
byteString[indexLength] = uint8(uname.Machine[indexLength])
|
||||
}
|
||||
return string(byteString[:indexLength])
|
||||
}
|
||||
|
||||
func GetKernel() (string, string) {
|
||||
uname := syscall.Utsname{}
|
||||
err := syscall.Uname(&uname)
|
||||
if err != nil {
|
||||
return "unknown", "unknown"
|
||||
}
|
||||
|
||||
var kernelNameByteString [65]byte
|
||||
var kernelNameLength int
|
||||
for ; uname.Sysname[kernelNameLength] != 0; kernelNameLength++ {
|
||||
kernelNameByteString[kernelNameLength] = uint8(uname.Sysname[kernelNameLength])
|
||||
}
|
||||
|
||||
var kernelReleaseByteString [65]byte
|
||||
var kernelReleaseLength int
|
||||
for ; uname.Release[kernelReleaseLength] != 0; kernelReleaseLength++ {
|
||||
kernelReleaseByteString[kernelReleaseLength] = uint8(uname.Release[kernelReleaseLength])
|
||||
}
|
||||
|
||||
return string(kernelNameByteString[:kernelNameLength]), string(kernelReleaseByteString[:kernelReleaseLength])
|
||||
}
|
||||
|
||||
func GetInitSystem() string {
|
||||
runCommand := func(command string) string {
|
||||
cmd := exec.Command("/bin/bash", "-c", command)
|
||||
cmd := exec.Command("/bin/sh", "-c", command)
|
||||
workdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return ""
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func GetShell() string {
|
||||
runCommand := func(command string) string {
|
||||
cmd := exec.Command("/bin/bash", "-c", command)
|
||||
cmd := exec.Command("/bin/sh", "-c", command)
|
||||
workdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return ""
|
||||
@@ -74,7 +74,7 @@ func GetDEWM() string {
|
||||
return slices.Contains(executables, process)
|
||||
}
|
||||
runCommand := func(command string) string {
|
||||
cmd := exec.Command("/bin/bash", "-c", command)
|
||||
cmd := exec.Command("/bin/sh", "-c", command)
|
||||
workdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return ""
|
||||
|
||||
Reference in New Issue
Block a user