package main import ( "bufio" "fmt" "os" "os/exec" "path/filepath" "strconv" "strings" ) const ( Reset = "\033[0m" GreenBold = "\033[1;32m" BlueBright = "\033[94m" ) var dist string type LinuxProvider struct{} func getDist() string { f, _ := os.Open("/etc/os-release") defer func(f *os.File) { err := f.Close() if err != nil { fmt.Println("Error closing file:", err) } }(f) s := bufio.NewScanner(f) for s.Scan() { t := s.Text() if strings.HasPrefix(t, "PRETTY_NAME") { distro := strings.TrimPrefix(t, "PRETTY_NAME=") dist = strings.Trim(distro, "\"") dist = strings.TrimSpace(dist) return dist } } return "unsupported distro" } func getRam() string { f, err := os.Open("/proc/meminfo") if err != nil { return "error" } var total, available int s := bufio.NewScanner(f) for s.Scan() { line := s.Text() if strings.HasPrefix(line, "MemTotal:") { _, err2 := fmt.Sscanf(line, "MemTotal: %d kB", &total) if err2 != nil { return "" } } if strings.HasPrefix(line, "MemAvailable:") { _, err := fmt.Sscanf(line, "MemAvailable: %d kB", &available) if err != nil { return "" } } } totalMB := total / 1024 availableMB := available / 1024 usedMB := totalMB - availableMB ram := fmt.Sprintf("%d / %d MiB (%d MiB available)", usedMB, totalMB, availableMB) ram = strings.TrimSpace(ram) return ram } func getCpu() string { f, err := os.Open("/proc/cpuinfo") if err != nil { return "error" } var cpu string s := bufio.NewScanner(f) for s.Scan() { line := s.Text() if strings.HasPrefix(line, "model name") { parts := strings.SplitN(line, ":", 2) if len(parts) > 1 { cpu := strings.TrimSpace(parts[1]) return cpu } } } cpu = fmt.Sprintf(cpu) cpu = strings.TrimSpace(cpu) return cpu } func (lp *LinuxProvider) getNvidiaGpuInfoPath() string { entries, err := os.ReadDir("/proc/driver/nvidia/gpus/") if err != nil { return "" } for _, entry := range entries { return filepath.Join("/proc/driver/nvidia/gpus/", entry.Name(), "information") } return "" } func (lp *LinuxProvider) findAmdGpuBase() string { for i := 0; i < 10; i++ { base := fmt.Sprintf("/sys/class/drm/card%d/device/", i) vendorPath := filepath.Join(base, "vendor") data, err := os.ReadFile(vendorPath) if err == nil { vendorID := strings.TrimSpace(string(data)) // 0x1002 — это PCI ID компании AMD if vendorID == "0x1002" { return base } } } return "" } func (lp *LinuxProvider) findStringInStreamWithDelimiter(filePath string, targetKey string, delimiter string) string { file, err := os.Open(filePath) if err != nil { return "" } scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, targetKey) { parts := strings.SplitN(line, delimiter, 2) if len(parts) > 1 { return strings.TrimSpace(parts[1]) } } } return "" } func (lp *LinuxProvider) getGpu() string { if _, err := os.Stat("/proc/driver/nvidia"); err == nil { path := lp.getNvidiaGpuInfoPath() if path != "" { name := lp.findStringInStreamWithDelimiter(path, "Model", ":") if name != "" { return name } } } else { base := lp.findAmdGpuBase() if base != "" { if data, err := os.ReadFile(filepath.Join(base, "product_name")); err == nil { name := strings.TrimSpace(string(data)) if name != "" { return name } } pci := lp.findStringInStreamWithDelimiter(filepath.Join(base, "uevent"), "PCI_ID", "=") if pci != "" && pci != "?" { return "AMD GPU (" + pci + ")" } return "AMD GPU" } } return "Unknown GPU" } func getKernel() string { out, err := exec.Command("sh", "-c", "uname -r").Output() if err != nil { return "Error getting kernel, how did we get there?" } return strings.TrimSpace(string(out)) } func getHostname() string { hostname, err := exec.Command("sh", "-c", "uname -n").Output() if err != nil { return "Error getting hostname, awful" } username, errUser := exec.Command("sh", "-c", "whoami").Output() if errUser != nil { return "Error getting username, nobody here but us chickens!" } fullHostname := fmt.Sprintf("%s@%s", strings.TrimSpace(string(username)), strings.TrimSpace(string(hostname))) return fullHostname } func getPkgs() string { var pkgs string if strings.HasPrefix(dist, "Arch") { out, _ := exec.Command("sh", "-c", "pacman -Qq | wc -l").Output() pkgs = strings.TrimSpace(string(out)) + " (pacman)" return pkgs } if strings.HasPrefix(dist, "Debian") { out, _ := exec.Command("sh", "-c", "dpkg -l | grep ^ii | wc -l").Output() pkgs = strings.TrimSpace(string(out)) + " (apt)" return pkgs } if strings.HasPrefix(dist, "NixOS") { entries, err := os.ReadDir("/run/current-system/sw/bin") if err != nil { return "can't get nix packages" } return strconv.Itoa(len(entries)) + " (nix)" } return "unknown" } func getAscii() string { var ascii string if strings.HasPrefix(dist, "Arch") { content := " _ _ _\n /\\ | | | | (_)\n / \\ _ __ ___| |__ | | _ _ __ _ ___ __\n / /\\ \\ | '__/ __| '_ \\ | | | | '_ \\| | | \\ \\/ /\n / ____ \\| | | (__| | | | | |____| | | | | |_| |> <\n /_/ \\_\\_| \\___|_| |_| |______|_|_| |_|\\__,_/_/\\_\\\n" ascii = fmt.Sprintf(content) return ascii } if strings.HasPrefix(dist, "Debian") { content := " _____ _ _\n | __ \\ | | (_)\n | | | | ___ | |__ _ __ _ _ __\n | | | | / _ \\ | '_ \\ | | / _` | | '_ \\\n | |__| | | __/ | |_) | | | | (_| | | | | |\n |_____/ \\___| |_.__/ |_| \\__,_| |_| |_|\n" ascii = fmt.Sprintf(content) return ascii } if strings.HasPrefix(dist, "NixOS") { content := " _ _ _ ____ _____\n | \\ | (_) / __ \\ / ____|\n | \\| |___ _| | | | (___\n | . ` | \\ \\/ / | | |\\___ \\\n | |\\ | |> <| |__| |____) |\n |_| \\_|_/_/\\_\\\\____/|_____/\n" ascii = fmt.Sprintf(content) return ascii } return "unknown" } func main() { type Info struct { Label string Value string } lp := &LinuxProvider{} stats := []Info{ {"distro", getDist()}, {"packages", getPkgs()}, {"kernel", getKernel()}, {"hostname", getHostname()}, {"memory", getRam()}, {"cpu", getCpu()}, {"gpu", lp.getGpu()}, } fmt.Print(BlueBright) fmt.Printf(getAscii()) fmt.Print(Reset) fmt.Printf("\n") fmt.Println("---------------------------") for _, s := range stats { fmt.Printf("> %s%s%s: %s\n", GreenBold, s.Label, Reset, s.Value) } }