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