commit edb34ed

Artur Manuel  ·  2026-05-05 01:16:33 +0000 UTC
parent 6a1109e
docs: add documentation for the project
11 files changed,  +179, -40
+2, -0
1@@ -11,3 +11,5 @@
2 !/README.md
3 !/assets
4 !/assets/**
5+!/docs
6+!/docs/**
+95, -0
 1@@ -0,0 +1,95 @@
 2+You've decided you want to use webfetch? This document should help you
 3+create a template for it. If you do not understand how you would even
 4+begin creating a template, feel free to read the following resources:
 5+
 6+- https://www.w3schools.com/html
 7+- https://www.w3schools.com/css
 8+- https://pkg.go.dev/text/template
 9+- https://pkg.go.dev/html/template
10+
11+# What variables can I use in my templates?
12+
13+There are quite a few, some admittedly redundant ones as well.
14+
15+## `.OS`
16+
17+The operating system running webfetch.
18+
19+**Example:** NixOS 26.05 (Yarara) 
20+
21+## `.Hostname`
22+
23+The hostname of the system running webfetch.
24+
25+**Example:** napoleon
26+
27+## `.Username`
28+
29+The username of the user running webfetch.
30+
31+**Example:** artur
32+
33+## `.KernelRelease`
34+
35+The release of the kernel you are using.
36+
37+**Example:** 6.18.26
38+
39+## `.KernelName`
40+
41+The name of the kernel you are using.
42+
43+**Example:** Linux
44+
45+## `.MachineArch`
46+
47+The architecture of your current machine.
48+
49+**Example:** x86_64
50+
51+## `.Shell`
52+
53+The shell you have set for your user.
54+
55+**Example:** /bin/bash
56+
57+## `.Uptime`
58+
59+The systems total uptime.
60+
61+**Example:** 67 days, 6 hours, 7 minutes, 0 seconds
62+
63+## `.Terminal`
64+
65+**Example:** alacritty
66+
67+## `.MemTotal`
68+
69+The total amount of memory you have, in kilobytes.
70+
71+**Example:** 6027
72+
73+## `.MemFree`
74+
75+The amount of free memory you have, in kilobytes.
76+
77+**Example:**
78+
79+## `.MemAvailable`
80+
81+The amount of available memory you have, in kilobytes.
82+
83+**Example:**
84+
85+## `.DesktopInfo` 
86+
87+The name of the desktop environment and display server you are using.
88+
89+**Example:** KDE Plasma (Wayland)
90+
91+## `.Locale`
92+
93+Your systems locale.
94+
95+**Example:** en_US
96+
+5, -3
 1@@ -11,7 +11,9 @@
 2 	- .Shell
 3 	- .Uptime
 4 	- .Terminal
 5-	- .MemInfo
 6+	- .MemTotal
 7+	- .MemFree
 8+	- .MemAvailable
 9 	- .DesktopInfo
10 
11 	I suggest reading https://pkg.go.dev/text/template to have a better
12@@ -92,8 +94,8 @@
13           <p>Terminal: {{ .Terminal }}</p>
14           <p>DE: {{ printf "%s" .DesktopInfo }}</p>
15           <p>Locale: {{ .Locale }}</p>
16-          {{ $memAvail := divide .MemInfo.MemAvailable 1000 }}
17-          {{ $memTotal := divide .MemInfo.MemTotal 1000 }}
18+          {{ $memAvail := divide .MemAvailable 1000 }}
19+          {{ $memTotal := divide .MemTotal 1000 }}
20           <p>Memory: {{ subtract $memTotal $memAvail }} MB / {{ $memTotal }} MB</p>
21         </div>
22       </div>
+1, -0
1@@ -2,6 +2,7 @@ package internal
2 
3 import "fmt"
4 
5+// DesktopInfo holds information about the desktop environment you are using.
6 type DesktopInfo struct {
7 	SessionType    string
8 	CurrentDesktop string
+1, -0
1@@ -8,6 +8,7 @@ import (
2 	"strings"
3 )
4 
5+// MemoryInfo mirroing the contents of /proc/meminfo
6 type MemoryInfo map[string]int
7 
8 func (info MemoryInfo) UnmarshalText(data []byte) error {
+1, -0
1@@ -7,6 +7,7 @@ import (
2 	"strings"
3 )
4 
5+// OsRelease is a set of key-value pairs mirroring what can be found in /etc/os-release.
6 type OsRelease map[string]string
7 
8 func (os OsRelease) UnmarshalText(text []byte) error {
+3, -0
 1@@ -8,6 +8,7 @@ import (
 2 	"strconv"
 3 )
 4 
 5+// PasswdEntry holds information about the user, such as their username, home directory, or shell.
 6 type PasswdEntry struct {
 7 	Username string
 8 	Password string
 9@@ -18,6 +19,7 @@ type PasswdEntry struct {
10 	Shell    string
11 }
12 
13+// A list of passwd entries, mirroring what you would find in /etc/passwd.
14 type Passwd []PasswdEntry
15 
16 func (passwd *PasswdEntry) UnmarshalText(text []byte) error {
17@@ -58,6 +60,7 @@ func (passwd *Passwd) UnmarshalText(text []byte) error {
18 	return nil
19 }
20 
21+// Get an entry from a list of passwd entries.
22 func (passwd Passwd) Entry(user string) (PasswdEntry, error) {
23 	if len(passwd) == 0 {
24 		return PasswdEntry{}, fmt.Errorf("passwd has no entries")
+15, -11
 1@@ -14,27 +14,33 @@ type SystemInfo struct {
 2 	Shell         string
 3 	Uptime        Uptime
 4 	Terminal      string
 5-	MemInfo       MemoryInfo
 6+	MemTotal      int
 7+	MemFree       int
 8+	MemAvailable  int
 9 	DesktopInfo   DesktopInfo
10 	Locale        string
11 }
12 
13 func GetSysinfo() (SystemInfo, error) {
14 	var sysinfo SystemInfo
15-	hostname, err := GetHostname()
16+	var uname syscall.Utsname
17+	if err := syscall.Uname(&uname); err != nil {
18+		return sysinfo, err
19+	}
20+	passwd, err := GetPasswd()
21 	if err != nil {
22 		return sysinfo, err
23 	}
24-	osRelease, err := GetOsRelease()
25+	hostname, err := GetNodename(uname)
26 	if err != nil {
27 		return sysinfo, err
28 	}
29-	username, err := GetUsername()
30+	osRelease, err := GetOsRelease()
31 	if err != nil {
32 		return sysinfo, err
33 	}
34-	var uname syscall.Utsname
35-	if err := syscall.Uname(&uname); err != nil {
36+	username, err := GetUsername()
37+	if err != nil {
38 		return sysinfo, err
39 	}
40 	kversion, err := GetKernelRelease(uname)
41@@ -49,10 +55,6 @@ func GetSysinfo() (SystemInfo, error) {
42 	if err != nil {
43 		return sysinfo, err
44 	}
45-	passwd, err := GetPasswd()
46-	if err != nil {
47-		return sysinfo, err
48-	}
49 	shell, err := GetShell(username, passwd)
50 	if err != nil {
51 		return sysinfo, err
52@@ -78,7 +80,9 @@ func GetSysinfo() (SystemInfo, error) {
53 	sysinfo.Shell = shell
54 	sysinfo.Uptime = up
55 	sysinfo.Terminal = terminal
56-	sysinfo.MemInfo = meminfo
57+	sysinfo.MemTotal = meminfo["MemTotal"]
58+	sysinfo.MemFree = meminfo["MemFree"]
59+	sysinfo.MemAvailable = meminfo["MemAvailable"]
60 	sysinfo.DesktopInfo = GetDesktopInfo()
61 	sysinfo.Locale = GetLocale()
62 	return sysinfo, nil
+18, -0
 1@@ -13,6 +13,8 @@ func cleanNulls(s string) string {
 2 	})
 3 }
 4 
 5+// Gets the name of the kernel using uname.
 6+// It returns the given kernel name and any errors it encounters.
 7 func GetKernelName(uname syscall.Utsname) (string, error) {
 8 	var b bytes.Buffer
 9 	for _, v := range uname.Sysname {
10@@ -23,6 +25,8 @@ func GetKernelName(uname syscall.Utsname) (string, error) {
11 	return cleanNulls(b.String()), nil
12 }
13 
14+// Gets the version of the kernel using uname.
15+// It returns the given kernel version and any errors it encounters.
16 func GetKernelRelease(uname syscall.Utsname) (string, error) {
17 	var b bytes.Buffer
18 	for _, v := range uname.Release {
19@@ -33,6 +37,8 @@ func GetKernelRelease(uname syscall.Utsname) (string, error) {
20 	return cleanNulls(b.String()), nil
21 }
22 
23+// Gets the machine's architecture using uname.
24+// It returns the given architecture and any errors it encounters.
25 func GetMachineArch(uname syscall.Utsname) (string, error) {
26 	var b bytes.Buffer
27 	for _, v := range uname.Machine {
28@@ -42,3 +48,15 @@ func GetMachineArch(uname syscall.Utsname) (string, error) {
29 	}
30 	return cleanNulls(b.String()), nil
31 }
32+
33+// Gets the machine's name using uname.
34+// It returns the given machine's name and any errors it encounters.
35+func GetNodename(uname syscall.Utsname) (string, error) {
36+	var b bytes.Buffer
37+	for _, v := range uname.Nodename {
38+		if err := b.WriteByte(byte(v)); err != nil {
39+			return "", fmt.Errorf("failed to write node name to buffer: %v", err)
40+		}
41+	}
42+	return cleanNulls(b.String()), nil
43+}
+1, -0
1@@ -7,6 +7,7 @@ import (
2 	"strconv"
3 )
4 
5+// Uptime of the system
6 type Uptime struct {
7 	Days    int
8 	Hours   int
+37, -26
  1@@ -6,7 +6,6 @@ import (
  2 	"io"
  3 	"os"
  4 	"path/filepath"
  5-	"strings"
  6 )
  7 
  8 var templateFuncMap = template.FuncMap{
  9@@ -16,6 +15,8 @@ var templateFuncMap = template.FuncMap{
 10 	"divide":   func(a int, b int) int { return a / b },
 11 }
 12 
 13+// Read /etc/passwd and collect all it's entries..
 14+// It returns the collected passwd entries and any errors it encounters.
 15 func GetPasswd() (Passwd, error) {
 16 	var passwd Passwd
 17 	text, err := os.ReadFile("/etc/passwd")
 18@@ -28,6 +29,8 @@ func GetPasswd() (Passwd, error) {
 19 	return passwd, nil
 20 }
 21 
 22+// Create an OsRelease by reading /etc/os-release.
 23+// It returns the resulting OsRelease or any errors it encounters.
 24 func GetOsRelease() (OsRelease, error) {
 25 	osRelease := make(OsRelease)
 26 	text, err := os.ReadFile("/etc/os-release")
 27@@ -40,21 +43,10 @@ func GetOsRelease() (OsRelease, error) {
 28 	return osRelease, nil
 29 }
 30 
 31-func GetHostname() (string, error) {
 32-	var sb strings.Builder
 33-	hostname, err := os.ReadFile("/etc/hostname")
 34-	if err != nil {
 35-		return "", fmt.Errorf("failed to read /etc/hostname: %v", err)
 36-	}
 37-	_, err = sb.Write(hostname)
 38-	if err != nil {
 39-		return "", fmt.Errorf("failed to use hostname: %v", err)
 40-	}
 41-	return strings.TrimSpace(sb.String()), nil
 42-}
 43-
 44+// Look up possible environment variables for usernames.
 45+// It returns the username given from the first non-empty environment variable, and any errors it encounters.
 46 func GetUsername() (string, error) {
 47-	userEnvVars := []string{"USER", "username"}
 48+	userEnvVars := []string{"USER", "USERNAME"}
 49 	var ok bool
 50 	var val string
 51 	for _, envvar := range userEnvVars {
 52@@ -69,14 +61,18 @@ func GetUsername() (string, error) {
 53 	return val, nil
 54 }
 55 
 56-func GetShell(user string, passwd Passwd) (string, error) {
 57-	pwEnt, err := passwd.Entry(user)
 58+// Using username and passwd, it tries to find the users shell.
 59+// It returns the user's shell, and any errors it encounters.
 60+func GetShell(username string, passwd Passwd) (string, error) {
 61+	pwEnt, err := passwd.Entry(username)
 62 	if err != nil {
 63 		return "", err
 64 	}
 65 	return pwEnt.Shell, nil
 66 }
 67 
 68+// Get the systems uptime by reading and parsing /proc/uptime
 69+// It returns the resulting uptime, and any errors it encounters.
 70 func GetUptime() (Uptime, error) {
 71 	var up Uptime
 72 	text, err := os.ReadFile("/proc/uptime")
 73@@ -89,18 +85,26 @@ func GetUptime() (Uptime, error) {
 74 	return up, nil
 75 }
 76 
 77+// Gets the users terminal by looking at given environment variables
 78+// It returns the given terminal, and any errors it encounters.
 79 func GetTerminal() (string, error) {
 80-	val, ok := os.LookupEnv("TERMINAL")
 81-	if ok {
 82-		return val, nil
 83+	termEnvVars := []string{"TERMINAL", "TERM"}
 84+	var result string
 85+	var ok bool
 86+	for _, variable := range termEnvVars {
 87+		result, ok = os.LookupEnv(variable)
 88+		if ok {
 89+			break
 90+		}
 91 	}
 92-	val, ok = os.LookupEnv("TERM")
 93-	if ok {
 94-		return val, nil
 95+	if !ok {
 96+		return "", fmt.Errorf("failed to find terminal")
 97 	}
 98-	return "", fmt.Errorf("failed to find terminal")
 99+	return result, nil
100 }
101 
102+// Get memory information by reading and parsing /proc/meminfo.
103+// It returns the resulting MemoryInfo, and any errors it encounters.
104 func GetMemoryInfo() (MemoryInfo, error) {
105 	meminfo := make(MemoryInfo)
106 	text, err := os.ReadFile("/proc/meminfo")
107@@ -113,6 +117,9 @@ func GetMemoryInfo() (MemoryInfo, error) {
108 	return meminfo, nil
109 }
110 
111+// Get information about the desktop environment by looking at the XDG environment variables.
112+// "Unknown" will be used in place of any environment variables which are missing.
113+// It returns the desktop information.
114 func GetDesktopInfo() DesktopInfo {
115 	var desktopInfo DesktopInfo
116 	currentDesktop, ok := os.LookupEnv("XDG_CURRENT_DESKTOP")
117@@ -128,6 +135,8 @@ func GetDesktopInfo() DesktopInfo {
118 	return desktopInfo
119 }
120 
121+// Get the system locale by looking at the LANG environment variable.
122+// It returns the system locale, or "Unknown" if nothing is found.
123 func GetLocale() string {
124 	locale, ok := os.LookupEnv("LANG")
125 	if !ok {
126@@ -136,13 +145,15 @@ func GetLocale() string {
127 	return locale
128 }
129 
130-func BuildTemplate(w io.Writer, file string, s SystemInfo) error {
131+// Builds the template found in file using sysinfo, and write it to w.
132+// It returns any errors that may have happened.
133+func BuildTemplate(w io.Writer, file string, sysinfo SystemInfo) error {
134 	name := filepath.Base(file)
135 	master, err := template.New(name).Funcs(templateFuncMap).ParseFiles(file)
136 	if err != nil {
137 		return fmt.Errorf("failed to parse %s: %v", file, err)
138 	}
139-	if err := master.ExecuteTemplate(w, name, s); err != nil {
140+	if err := master.ExecuteTemplate(w, name, sysinfo); err != nil {
141 		return fmt.Errorf("failed to write template to writer: %v", err)
142 	}
143 	return nil