37 Commits
Author SHA1 Message Date
EnumDev cd0faaefe5 Add Enit init system detection 2025-03-10 22:43:06 +02:00
EnumDev 4b9bc59810 Change init system checking code 2025-03-10 22:42:18 +02:00
EnumDev 0ed976a06e Fixed bug where the getDistroAsciiArt function would ignore the systemConfigDir variable 2025-02-06 21:18:55 +02:00
EnumDev ce9813a2af Made fatal errors clearer and fixed bug in fetch script 2025-02-06 21:18:55 +02:00
EnumDev 0d3d3fafb2 Added motherboard information 2025-02-06 21:18:55 +02:00
EnumDev a99defd401 Makefile will now always use bash 2025-02-06 21:18:55 +02:00
EnumDev f34537eb5a Updated README.md 2025-01-24 18:10:17 +00:00
EnumDev 120a1cf8e4 Fix for Xfce 2024-11-04 13:37:57 +02:00
EnumDev 76974ee789 Added i3, swayfx and hyprland WM detection 2024-10-23 17:14:23 +03:00
EnumDev 20cf7fe869 Fixed error when attempting to use stormfetch without being connected to the internet and simplified fetch script 2024-09-06 19:07:45 +03:00
EnumDev c5e02c07b5 Added wayland monitor resolution support 2024-08-23 15:13:09 +03:00
EnumDev e8a95e5313 Added Local IPv4 address support 2024-08-23 14:32:26 +03:00
EnumDev 0fd198d83e Added init system support 2024-08-22 21:54:14 +03:00
EnumDev 673f231c42 Added nushell support 2024-08-22 21:25:46 +03:00
CapCreeperGR e311649a48 Added PopOS ascii 2024-07-18 15:35:14 +03:00
CapCreeperGR 712fd78e21 Updated tide ascii 2024-07-18 14:12:45 +03:00
CapCreeperGR 7d83b0996d Improved GPU and added --time-taken flag 2024-07-17 20:11:30 +03:00
CapCreeperGR f3a016b674 Added Libc information 2024-07-17 13:18:31 +03:00
CapCreeperGR 0e2631d5b0 Added Artix ascii 2024-07-16 20:55:06 +03:00
EnumDev 153758b68e make should now be able to locate the go executable more easily 2024-07-01 13:16:37 +03:00
EnumDev ed45b739a5 Updated BPM package count fetching 2024-07-01 12:44:22 +03:00
EnumDev 8c380dbec4 Stormfetch can now read config files in the directory specified with the Makefile SYSCONFDIR variable 2024-06-20 21:23:50 +03:00
EnumDev 7c493dc9f9 Added filesystem label detection, btrfs subvolumes should now be grouped under one partition and the filesystem type will now be shown if enabled in config.yaml 2024-06-19 18:20:16 +03:00
EnumDev b8d7017299 Fixed bug where xbps packages would be counted on arch systems and not void systems 2024-06-18 07:49:19 +03:00
EnumDev cd08003752 Fixed emerge package count and added VoidLinux/xbps support 2024-06-17 19:41:20 +03:00
EnumDev c4c71fc49a Added hidden_gpus option in the config 2024-06-09 14:45:17 +03:00
EnumDev efdbe94193 Stormfetch will now list all GPUs if multiple of them are connected 2024-06-09 14:39:24 +03:00
EnumDev 7b8c017ed0 Added a --distro-name flag and distro_name config option 2024-06-09 11:11:18 +03:00
EnumDev 66f3891b40 Slightly changed ubuntu ascii to fix a minor spacing bug 2024-06-09 10:52:01 +03:00
EnumDev efae7c4b93 Split main.go code into more functions,improved extra newline removal and added --ascii flag 2024-06-09 10:49:11 +03:00
EnumDev 24da6ce083 Removed extra new lines at the end of the output 2024-06-09 10:30:55 +03:00
EnumDev b90b869643 Stormfetch will no longer crash if there is an error while reading partition size 2024-06-09 10:20:28 +03:00
EnumDev 720eb845ca Improved partition detection 2024-06-09 10:12:36 +03:00
EnumDev 81c4006e48 Removed .gitignore from repository due to being unnecessary 2024-06-09 09:45:28 +03:00
EnumDev 58b3e82346 Added Linux Mint ascii 2024-06-08 20:47:33 +03:00
EnumDev ba67c074db Fixed bug where system info would be cut off if ascii was short and added cachyos ascii 2024-06-08 20:33:33 +03:00
EnumDev c8b3f9f4a4 Text color should now reset at the end of the stormfetch output 2024-06-05 16:43:27 +03:00
18 changed files with 497 additions and 214 deletions
-4
View File
@@ -1,4 +0,0 @@
.idea
build
stormfetch
stormfetch.tar.gz
+6 -2
View File
@@ -1,3 +1,5 @@
SHELL := /bin/bash
ifeq ($(PREFIX),)
PREFIX := /usr/local
endif
@@ -8,12 +10,12 @@ ifeq ($(SYSCONFDIR),)
SYSCONFDIR := $(PREFIX)/etc
endif
ifeq ($(GO),)
GO := /usr/bin/go
GO := $(shell type -a -P go | head -n 1)
endif
build:
mkdir -p build
$(GO) build -ldflags "-w" -o build/stormfetch stormfetch
$(GO) build -ldflags "-w -X 'main.systemConfigDir=$(SYSCONFDIR)'" -o build/stormfetch stormfetch
install: build/stormfetch config/
mkdir -p $(DESTDIR)$(BINDIR)
@@ -34,3 +36,5 @@ run: build/stormfetch
clean:
rm -r build/
.PHONY: build
+2 -2
View File
@@ -3,7 +3,7 @@
## A simple linux fetch program written in go and bash
### Developers:
- [CapCreeperGR ](https://gitlab.com/CapCreeperGR)
- [EnumDev](https://gitlab.com/EnumDev)
### Project Information
Stormfetch is a program that can read your system's information and display it in the terminal along with the ASCII art of the Linux distribution you are running.
@@ -20,7 +20,7 @@ Stormfetch is still in beta, so distro compatibility is limited. If you would li
- Download `make` from your package manager
- Run the following command to compile the project
```
make
make SYSCONFDIR=/etc
```
- Run the following command to install stormfetch into your system. You may also append a DESTDIR variable at the end of this line if you wish to install in a different location
```
+20
View File
@@ -0,0 +1,20 @@
#/45;27;45;7
${C1} 'o'
'ooo'
'ooxoo'
'ooxxxoo'
'oookkxxoo'
'oiioxkkxxoo'
':;:iiiioxxxoo'
`'.;::ioxxoo'
'-. `':;jiooo'
'oooio-.. `'i:io'
'ooooxxxxoio:,. `'-;'
'ooooxxxxxkkxoooIi:-. `'
'ooooxxxxxkkkkxoiiiiiji'
'ooooxxxxxkxxoiiii:'` .i'
'ooooxxxxxoi:::'` .;ioxo'
'ooooxooi::'` .:iiixkxxo'
'ooooi:'` `'';ioxxo'
'i:'` '':io'
'` `'
+23
View File
@@ -0,0 +1,23 @@
#/43;45;45;15
${C3}.${C1}-------------------------:
.${C2}+=${C1}========================.
:${C2}++${C1}===${C2}++===${C1}===============- :${C2}++${C1}-
:${C2}*++${C1}====${C2}+++++==${C1}===========- .==:
-${C2}*+++${C1}=====${C2}+***++=${C1}=========:
=${C2}*++++=${C1}=======------------:
=${C2}*+++++=${C1}====- ${C3}...${C1}
.${C2}+*+++++${C1}=-===: .${C2}=+++=${C1}:
:${C2}++++${C1}=====-==: -***${C2}**${C1}+
:${C2}++=${C1}=======-=. .=+**+${C3}.${C1}
.${C2}+${C1}==========-. ${C3}.${C1}
:${C2}+++++++${C1}====- ${C3}.${C1}--==-${C3}.${C1}
:${C2}++${C1}==========. ${C3}:${C2}+++++++${C1}${C3}:
${C1}.-===========. =*****+*+
${C1}.-===========: .+*****+:
${C1}-=======${C2}++++${C1}:::::::::::::::::::::::::-: ${C3}.${C1}---:
:======${C2}++++${C1}====${C2}+++******************=.
${C1}:=====${C2}+++${C1}==========${C2}++++++++++++++*-
${C1}.====${C2}++${C1}==============${C2}++++++++++*-
${C1}.===${C2}+${C1}==================${C2}+++++++:
${C1}.-=======================${C2}+++:
${C3}..........................
+20
View File
@@ -0,0 +1,20 @@
#/34;15;46;252
${C2} ...-:::::-...
${C2} .-MMMMMMMMMMMMMMM-.
.-MMMM${C1}`..-:::::::-..`${C2}MMMM-.
.:MMMM${C1}.:MMMMMMMMMMMMMMM:.${C2}MMMM:.
-MMM${C1}-M---MMMMMMMMMMMMMMMMMMM.${C2}MMM-
`:MMM${C1}:MM` :MMMM:....::-...-MMMM:${C2}MMM:`
:MMM${C1}:MMM` :MM:` `` `` `:MMM:${C2}MMM:
.MMM${C1}.MMMM` :MM. -MM. .MM- `MMMM.${C2}MMM.
:MMM${C1}:MMMM` :MM. -MM- .MM: `MMMM-${C2}MMM:
:MMM${C1}:MMMM` :MM. -MM- .MM: `MMMM:${C2}MMM:
:MMM${C1}:MMMM` :MM. -MM- .MM: `MMMM-${C2}MMM:
.MMM${C1}.MMMM` :MM:--:MM:--:MM: `MMMM.${C2}MMM.
:MMM${C1}:MMM- `-MMMMMMMMMMMM-` -MMM-${C2}MMM:
:MMM${C1}:MMM:` `:MMM:${C2}MMM:
.MMM${C1}.MMMM:--------------:MMMM.${C2}MMM.
'-MMMM${C1}.-MMMMMMMMMMMMMMM-.${C2}MMMM-'
'.-MMMM${C1}``--:::::--``${C2}MMMM-.'
${C2} '-MMMMMMMMMMMMM-'
${C2} ``-:::::-``
+21
View File
@@ -0,0 +1,21 @@
#/33;7;11;15
${C1} /////////////
/////////////////////
///////${C2}*767${C1}////////////////
//////${C2}7676767676*${C1}//////////////
/////${C2}76767${C1}//${C2}7676767${C1}//////////////
/////${C2}767676${C1}///${C2}*76767${C1}///////////////
///////${C2}767676${C1}///${C2}76767${C1}.///${C2}7676*${C1}///////
/////////${C2}767676${C1}//${C2}76767${C1}///${C2}767676${C1}////////
//////////${C2}76767676767${C1}////${C2}76767${C1}/////////
///////////${C2}76767676${C1}//////${C2}7676${C1}//////////
////////////,${C2}7676${C1},///////${C2}767${C1}///////////
/////////////*${C2}7676${C1}///////${C2}76${C1}////////////
///////////////${C2}7676${C1}////////////////////
///////////////${C2}7676${C1}///${C2}767${C1}////////////
//////////////////////${C2}'${C1}////////////
//////${C2}.7676767676767676767,${C1}//////
/////${C2}767676767676767676767${C1}/////
///////////////////////////
/////////////////////
/////////////
+15 -18
View File
@@ -1,18 +1,15 @@
#/6;10;5;12
${C1} @@@@@@@@@
@@@~~~~~~~~~@@
@@~~~ ~~@
@~~ @
@~ @@@ @
@@~ @ @@
@@~~ @
@@@~~ ~@@ @@@
~~~ ~~@@@ @@@@~~~
~~~@@@@~~~~
@@@@ @@@@@@@ ~~~~ @@@@
~~~~@@@@ @@~~~~~~~@@ @@@@
~~~~@@@@~~ ~~@@@@~~~~
@@@ ~~~~ @@@@@ ~~~~ @@@
~~~@@@@ @@@@~~~~~@@@@ @@@@~~~
~~~~@@@~~~~ ~~~~@@@~~~
~~~ ~~~
#/27;39;5;12
${C1}@@@@ ${C1}@@@${C2}*
${C1}@@${C2}~~~~${C1}@@ ${C1}@@${C2}~~~
${C1}@@${C2}~~ ${C2}~~${C1}@ ${C1}@@${C2}~~
${C1}@@${C2}~~ ${C2}~${C1}@ ${C1}@@@${C2}~~
${C2}*${C1}@@${C2}~~ ${C1}@@@@ ${C2}~${C1}@@@@${C2}~~~ ${C1}@@@${C2}*
${C2}~~ ${C1}@@${C2}~~~~${C1}@@ ${C2}~~~~ ${C1}@@${C2}~~~
${C1}@@${C2}~~ ${C2}~~${C1}@ ${C1}@@${C2}~~
${C1}@@${C2}~~ ${C2}~${C1}@ ${C1}@@@${C2}~~
${C2}*${C1}@@${C2}~~ ${C1}@@@@ ${C2}~${C1}@@@@${C2}~~~ ${C1}@@@${C2}*
${C2}~~ ${C1}@@${C2}~~~~${C1}@@ ${C2}~~~~ ${C1}@@${C2}~~~
${C1}@@${C2}~~ ${C2}~~${C1}@ ${C1}@@${C2}~~
${C1}@@${C2}~~ ${C2}~${C1}@ ${C1}@@@${C2}~~
${C2}*${C1}@@${C2}~~ ${C2}~${C1}@@@@${C2}~~~
${C2}~~ ${C2}~~~~
+2 -2
View File
@@ -1,6 +1,6 @@
#/1;7;3;15
${C1} .-/+oossssoo+\-.
´:+ssssssssssssssssss+:`
':+ssssssssssssssssss+:'
-+ssssssssssssssssssyyssss+-
.ossssssssssssssssss${C2}dMMMNy${C1}sssso.
/sssssssssss${C2}hdmmNNmmyNMMMMh${C1}ssssss\
@@ -17,5 +17,5 @@ oss${C2}yNMMMNyMMh${C1}sssssssssssssshmmmh${C1}ssssssso
\sssssssssss${C2}hdmNNNNmyNMMMMh${C1}ssssss/
.ossssssssssssssssss${C2}dMMMNy${C1}sssso.
-+sssssssssssssssss${C2}yyy${C1}ssss+-
`:+ssssssssssssssssss+:`
':+ssssssssssssssssss+:'
.-\+oossssoo+/-.
+19
View File
@@ -0,0 +1,19 @@
#/2;36;72;15
${C2}:::::----:::::
${C2}::----------------::=
${C2}:-------------------::
${C1} : ${C2}:::. ..:-------:
${C1} =*=. ${C2}.:-----:
${C1} =****- ${C2}:-----:
${C1}=*****- ${C2}:::::: :-----:
${C1}=****+ ${C2}:--------: :----:
${C1}+****- ${C2}.----------. :----:
${C1}+****- ${C2}.----------. :-----
${C1}=****+ ${C2}:--------: :----:
${C1}=*****- ${C2}:::::: :-----:
${C1} =*****- ${C2}:----:
${C1} =*****+: ${C2}:-:
${C1} =*******=:: ::=-. ${C2}.
${C1} ==*******************-
${C1} ===****************=-
${C1} ===+=****++===
+2
View File
@@ -3,3 +3,5 @@ fetch_script: auto
ansii_colors: []
force_config_ansii: false
dependency_warning: true
show_fs_type: true
hidden_gpus: []
+26 -8
View File
@@ -5,26 +5,44 @@ echo -e "${C3}Hostname: ${C4}$(cat /etc/hostname)"
echo -e "${C3}Kernel: ${C4}$(uname -s) $(uname -r)"
echo -e "${C3}Packages: ${C4}$(get_packages)"
echo -e "${C3}Shell: ${C4}${USER_SHELL}"
if [ ! -z "$CPU_MODEL" ]; then echo -e "${C3}CPU: ${C4}${CPU_MODEL} (${CPU_THREADS} threads)"; fi
if [ ! -z "$GPU_MODEL" ]; then echo -e "${C3}GPU: ${C4}${GPU_MODEL}"; fi
if [ ! -z "$MEM_TOTAL" ] && [ ! -z "$MEM_USED" ]; then echo -e "${C3}Memory: ${C4}${MEM_USED} MiB / ${MEM_TOTAL} MiB"; fi
for i in $(seq ${MOUNTED_PARTITIONS}); do
device="PARTITION${i}_DEVICE"
echo -e "${C3}Init: ${C4}${INIT_SYSTEM}"
echo -e "${C3}Libc: ${C4}${LIBC}"
[ -n "$MOTHERBOARD" ] && echo -e "${C3}Motherboard: ${C4}${MOTHERBOARD}"
[ -n "$CPU_MODEL" ] && echo -e "${C3}CPU: ${C4}${CPU_MODEL} (${CPU_THREADS} threads)"
for i in $(seq "${CONNECTED_GPUS}"); do
gpu="GPU$i"
echo -e "${C3}GPU: ${C4}${!gpu}"
done
[ -n "$MEM_TOTAL" ] && [ -n "$MEM_USED" ] && echo -e "${C3}Memory: ${C4}${MEM_USED} MiB / ${MEM_TOTAL} MiB"
for i in $(seq "${MOUNTED_PARTITIONS}"); do
mountpoint="PARTITION${i}_MOUNTPOINT"
label="PARTITION${i}_LABEL"
type="PARTITION${i}_TYPE"
total="PARTITION${i}_TOTAL_SIZE"
used="PARTITION${i}_USED_SIZE"
if [ -z "${!type}" ]; then
if [ -z "${!label}" ]; then
echo -e "${C3}Partition ${!mountpoint}: ${C4}${!used}/${!total}"
else
echo -e "${C3}Partition ${!label}: ${C4}${!used}/${!total}"
fi
else
if [ -z "${!label}" ]; then
echo -e "${C3}Partition ${!mountpoint} (${!type}): ${C4}${!used}/${!total}"
else
echo -e "${C3}Partition ${!label} (${!type}): ${C4}${!used}/${!total}"
fi
fi
done
if [ ! -z "$DISPLAY_PROTOCOL" ]; then
[ -n "$LOCAL_IPV4" ] && echo -e "${C3}Local IPv4 Address: ${C4}${LOCAL_IPV4}"
if [ -n "$DISPLAY_PROTOCOL" ]; then
echo -e "${C3}Display Protocol: ${C4}${DISPLAY_PROTOCOL}"
for i in $(seq ${CONNECTED_MONITORS}); do
for i in $(seq "${CONNECTED_MONITORS}"); do
monitor="MONITOR$i"
echo -e "${C3}Screen $i: ${C4}${!monitor}"
done
fi
if [ ! -z "$DE_WM" ]; then echo -e "${C3}DE/WM: ${C4}${DE_WM}"; fi
[ -n "$DE_WM" ] && echo -e "${C3}DE/WM: ${C4}${DE_WM}"
# Exiting with error code 0 in case the condition above returns 1
exit 0
+5 -2
View File
@@ -20,11 +20,14 @@ get_packages() {
if command_exists rpm; then
ARRAY+=("$(rpm -qa | wc -l) (rpm)")
fi
if command_exists xbps-query; then
ARRAY+=("$(xbps-query -l | wc -l) (xbps)")
fi
if command_exists bpm; then
ARRAY+=("$(bpm list -n) (bpm)")
ARRAY+=("$(bpm list -c) (bpm)")
fi
if command_exists emerge; then
ARRAY+=("$(ls -l /var/db/pkg/ | wc -l) (emerge)")
ARRAY+=("$(ls -l /var/db/pkg/* | wc -l) (emerge)")
fi
if command_exists flatpak; then
ARRAY+=("$(flatpak list | wc -l) (flatpak)")
+2
View File
@@ -10,10 +10,12 @@ require (
)
require (
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/jackmordaunt/pcidb v1.0.1 // indirect
github.com/jackmordaunt/wmi v1.2.4 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/moby/sys/mountinfo v0.7.1 // indirect
golang.org/x/sys v0.3.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
+5
View File
@@ -1,5 +1,7 @@
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc h1:7D+Bh06CRPCJO3gr2F7h1sriovOZ8BMhca2Rg85c2nk=
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/jackmordaunt/ghw v1.0.4 h1:as+COFuPuXaNQC3WqzoHS/E2JYWZU7gN8ompNTUxNxs=
@@ -15,7 +17,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+145 -64
View File
@@ -1,8 +1,9 @@
package main
import (
"flag"
"fmt"
yaml "gopkg.in/yaml.v3"
"gopkg.in/yaml.v3"
"log"
"os"
"os/exec"
@@ -10,39 +11,52 @@ import (
"regexp"
"strconv"
"strings"
"time"
)
var systemConfigDir = "/etc/"
var configPath = ""
var fetchScriptPath = ""
var TimeTaken = false
var config = StormfetchConfig{
Ascii: "auto",
FetchScript: "auto",
AnsiiColors: make([]int, 0),
ForceConfigAnsii: false,
DependencyWarning: true,
ShowFSType: false,
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"`
DependencyWarning bool `yaml:"dependency_warning"`
ShowFSType bool `yaml:"show_fs_type"`
HiddenGPUS []int `yaml:"hidden_gpus"`
}
func main() {
readConfig()
readFlags()
checkDependencies()
runStormfetch()
}
func readConfig() {
// Get home directory
configDir, _ := os.UserConfigDir()
userConfigDir, _ := os.UserConfigDir()
// Find valid config directory
if _, err := os.Stat(path.Join(configDir, "stormfetch/config.yaml")); err == nil {
configPath = path.Join(configDir, "stormfetch/config.yaml")
} else if _, err := os.Stat("/etc/stormfetch/config.yaml"); err == nil {
configPath = "/etc/stormfetch/config.yaml"
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())
}
@@ -65,13 +79,23 @@ func readConfig() {
log.Fatalf("Fetch script path points to a directory")
}
}
if _, err := os.Stat(path.Join(configDir, "stormfetch/fetch_script.sh")); err == nil {
fetchScriptPath = path.Join(configDir, "stormfetch/fetch_script.sh")
} else if _, err := os.Stat("/etc/stormfetch/fetch_script.sh"); err == nil {
fetchScriptPath = "/etc/stormfetch/fetch_script.sh"
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() {
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.Parse()
}
func checkDependencies() {
// Show Dependency warning if enabled
if config.DependencyWarning {
var dependencies []string
@@ -89,6 +113,100 @@ func readConfig() {
fmt.Println("You can disable this warning through your stormfetch config")
}
}
}
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.Println(fmt.Sprintf("Setting '%s' took %d milliseconds", key, end-start))
}
}
setVariable("DISTRO_LONG_NAME", func() string { return getDistroInfo().LongName })
setVariable("DISTRO_SHORT_NAME", func() string { return getDistroInfo().ShortName })
setVariable("CPU_MODEL", func() string { return getCPUName() })
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.Println(fmt.Sprintf("Setting '%s' took %d milliseconds", "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()
end = time.Now().UnixMilli()
if showTimeTaken {
fmt.Println(fmt.Sprintf("Setting '%s' took %d milliseconds", "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.Type != "" && config.ShowFSType {
env["PARTITION"+strconv.Itoa(i+1)+"_TYPE"] = part.Type
}
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.Println(fmt.Sprintf("Setting '%s' took %d milliseconds", "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 := getGPUNames()
end = time.Now().UnixMilli()
if showTimeTaken {
fmt.Println(fmt.Sprintf("Setting '%s' took %d milliseconds", "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 and apply colors
colorMap := make(map[string]string)
colorMap["C0"] = "\033[0m"
@@ -135,14 +253,14 @@ func readConfig() {
cmd := exec.Command("/bin/bash", fetchScriptPath)
cmd.Dir = path.Dir(fetchScriptPath)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, SetupFetchEnv()...)
cmd.Env = append(cmd.Env, SetupFetchEnv(TimeTaken)...)
cmd.Env = append(cmd.Env, "C0=\033[0m")
for key, value := range colorMap {
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
}
out, err := cmd.Output()
if err != nil {
log.Fatal(err)
log.Fatalf("Error: Could not run fetch script: %s", err)
}
// Print Distro Information
maxWidth := 0
@@ -152,9 +270,19 @@ func readConfig() {
}
}
final := ""
for lineIndex, line := range asciiSplit {
lineVisibleLength := len(strings.Split(asciiNoColor, "\n")[lineIndex])
y := len(asciiSplit)
if len(asciiSplit) < len(strings.Split(string(out), "\n")) {
y = len(strings.Split(string(out), "\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)
@@ -166,60 +294,13 @@ func readConfig() {
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"
}
fmt.Println(final)
}
func SetupFetchEnv() []string {
var env = make(map[string]string)
env["DISTRO_LONG_NAME"] = getDistroInfo().LongName
env["DISTRO_SHORT_NAME"] = getDistroInfo().ShortName
env["CPU_MODEL"] = getCPUName()
env["CPU_THREADS"] = strconv.Itoa(getCPUThreads())
memory := GetMemoryInfo()
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)
}
partitions := getMountedPartitions()
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
}
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)
}
}
env["DE_WM"] = GetDEWM()
env["USER_SHELL"] = GetShell()
env["DISPLAY_PROTOCOL"] = GetDisplayProtocol()
monitors := getMonitorResolution()
if len(monitors) != 0 {
env["CONNECTED_MONITORS"] = strconv.Itoa(len(monitors))
for i, monitor := range monitors {
env["MONITOR"+strconv.Itoa(i+1)] = monitor
}
}
if getGPUName() != "" {
env["GPU_MODEL"] = getGPUName()
}
var ret = make([]string, len(env))
i := 0
for key, value := range env {
ret[i] = fmt.Sprintf("%s=%s", key, value)
i++
}
return ret
final = strings.TrimRight(final, "\n\t ")
fmt.Println(final + "\033[0m")
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 121 KiB

+158 -86
View File
@@ -3,12 +3,13 @@ package main
import (
"bufio"
"fmt"
"github.com/BurntSushi/xgb"
"github.com/BurntSushi/xgb/xinerama"
"github.com/go-gl/glfw/v3.3/glfw"
"github.com/jackmordaunt/ghw"
"github.com/mitchellh/go-ps"
"github.com/moby/sys/mountinfo"
"log"
"math"
"net"
"os"
"os/exec"
"path"
@@ -27,41 +28,32 @@ type DistroInfo struct {
}
func getDistroInfo() DistroInfo {
distroID := ""
info := DistroInfo{
ID: "unknown",
LongName: "Unknown",
ShortName: "Unknown",
}
if strings.TrimSpace(config.DistroName) != "" {
info.LongName = strings.TrimSpace(config.DistroName)
info.ShortName = strings.TrimSpace(config.DistroName)
}
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",
return info
}
}
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,
info.ID = id
}
if longName, ok := releaseMap["PRETTY_NAME"]; ok && info.LongName == "Unknown" {
info.LongName = longName
}
if shortName, ok := releaseMap["NAME"]; ok && info.ShortName == "Unknown" {
info.ShortName = shortName
}
}
return DistroInfo{
ID: "unknown",
LongName: "Unknown",
ShortName: "Unknown",
}
}
return info
}
func getDistroAsciiArt() string {
@@ -81,8 +73,8 @@ func getDistroAsciiArt() string {
}
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 := os.Stat(path.Join(systemConfigDir, "stormfetch/ascii/", id)); err == nil {
bytes, err := os.ReadFile(path.Join(systemConfigDir, "stormfetch/ascii/", id))
if err != nil {
return defaultAscii
}
@@ -97,17 +89,25 @@ func getDistroAsciiArt() string {
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))
} else if _, err := os.Stat(path.Join(systemConfigDir, "stormfetch/ascii/", id)); err == nil {
bytes, err := os.ReadFile(path.Join(systemConfigDir, "stormfetch/ascii/", id))
if err != nil {
return defaultAscii
}
return string(bytes)
return strings.TrimRight(string(bytes), "\n\t ")
} else {
return defaultAscii
}
}
func getMotherboardModel() string {
bytes, err := os.ReadFile("/sys/devices/virtual/dmi/id/board_name")
if err != nil {
return ""
}
return strings.TrimSpace(string(bytes))
}
func getCPUName() string {
cpu, err := ghw.CPU()
if err != nil {
@@ -127,22 +127,21 @@ func getCPUThreads() int {
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
func getGPUNames() []string {
var ret []string
cmd := exec.Command("/bin/bash", "-c", "lspci -v -m | grep 'VGA' -A6 | grep '^Device:' | sed 's/^Device://' | awk '{$1=$1};1'")
bytes, err := cmd.Output()
if err != nil {
return ""
return nil
}
for _, graphics := range gpu.GraphicsCards {
if graphics.DeviceInfo != nil {
return graphics.DeviceInfo.Product.Name
for _, name := range strings.Split(string(bytes), "\n") {
name = strings.TrimSpace(name)
if name == "" {
continue
}
ret = append(ret, name)
}
return ""
return ret
}
type Memory struct {
@@ -235,6 +234,8 @@ func GetShell() string {
return "Zsh " + runCommand("$SHELL --version | awk '{print $2}'")
case "fish":
return "Fish " + runCommand("$SHELL --version | awk '{print $3}'")
case "nu":
return "Nushell " + runCommand("$SHELL --version")
default:
return "Unknown"
}
@@ -243,7 +244,7 @@ func GetShell() string {
func GetDEWM() string {
processes, err := ps.Processes()
if err != nil {
log.Fatal(err)
log.Fatalf("Error: could not get processes: %s", err)
}
var executables []string
for _, process := range processes {
@@ -267,23 +268,30 @@ func GetDEWM() string {
}
return strings.TrimSpace(string(out))
}
if processExists("plasmashell") {
return "KDE Plasma " + runCommand("plasmashell --version | awk '{print $2}'")
} else if processExists("gnome-session") {
return "Gnome " + runCommand("gnome-shell --version | awk '{print $3}'")
} else if processExists("xfce4-session") {
return "XFCE " + runCommand("xfce4-session --version | grep xfce4-session | awk '{print $2}'")
return "XFCE " + runCommand("xfce4-session --version | head -n1 | awk '{print $2}'")
} else if processExists("cinnamon") {
return "Cinnamon " + runCommand("cinnamon --version | awk '{print $3}'")
} else if processExists("mate-panel") {
return "MATE " + runCommand("mate-about --version | awk '{print $4}'")
} else if processExists("lxsession") {
return "LXDE"
} else if processExists("i3") {
return "i3 " + runCommand("i3 --version | awk '{print $3}'")
} else if processExists("sway") {
if runCommand("sway --version | awk '{print $1}'") == "swayfx" {
return "SwayFX " + runCommand("sway --version | awk '{print $3}'")
} else {
return "Sway " + runCommand("sway --version | awk '{print $3}'")
}
} else if processExists("bspwm") {
return "Bspwm " + runCommand("bspwm -v")
} else if processExists("Hyprland") {
return "Hyprland " + runCommand("hyprctl version | sed -n 3p | awk '{print $2}' | tr -d 'v,'")
} else if processExists("icewm-session") {
return "IceWM " + runCommand("icewm --version | awk '{print $2}'")
}
@@ -302,20 +310,16 @@ func GetDisplayProtocol() string {
func getMonitorResolution() []string {
var monitors []string
if GetDisplayProtocol() == "X11" {
conn, err := xgb.NewConn()
if GetDisplayProtocol() != "" {
err := glfw.Init()
if err != nil {
return nil
panic(err)
}
err = xinerama.Init(conn)
if err != nil {
return nil
}
reply, _ := xinerama.QueryScreens(conn).Reply()
conn.Close()
for _, screen := range reply.ScreenInfo {
monitors = append(monitors, strconv.Itoa(int(screen.Width))+"x"+strconv.Itoa(int(screen.Height)))
for _, monitor := range glfw.GetMonitors() {
mode := monitor.GetVideoMode()
monitors = append(monitors, fmt.Sprintf("%dx%d %dHz", mode.Width, mode.Height, mode.RefreshRate))
}
defer glfw.Terminate()
}
return monitors
}
@@ -324,17 +328,20 @@ type partition struct {
Device string
MountPoint string
Label string
Type string
TotalSize uint64
UsedSize uint64
FreeSize uint64
}
func getMountedPartitions() []partition {
partuuids, err := os.ReadDir("/dev/disk/by-partuuid")
if err != nil {
mounts, err := mountinfo.GetMounts(func(info *mountinfo.Info) (skip, stop bool) {
return !strings.HasPrefix(info.Source, "/dev/"), false
})
fslabels, err := os.ReadDir("/dev/disk/by-label")
if err != nil && !os.IsNotExist(err) {
return nil
}
partlabels, err := os.ReadDir("/dev/disk/by-partlabel")
if err != nil && !os.IsNotExist(err) {
return nil
@@ -347,47 +354,40 @@ func getMountedPartitions() []partition {
}
labels[link] = entry.Name()
}
bytes, err := os.ReadFile("/proc/mounts")
for _, entry := range fslabels {
link, err := filepath.EvalSymlinks(filepath.Join("/dev/disk/by-label/", entry.Name()))
if err != nil {
return nil
}
mountsRaw := strings.Split(string(bytes), "\n")
mounts := make(map[string]string)
for i := 0; i < len(mountsRaw); i++ {
split := strings.Split(mountsRaw[i], " ")
if len(split) <= 2 {
continue
}
mounts[split[0]] = split[1]
labels[link] = entry.Name()
}
var partitions []partition
for _, entry := range partuuids {
link, err := filepath.EvalSymlinks(filepath.Join("/dev/disk/by-partuuid/", entry.Name()))
if err != nil {
continue
}
if _, ok := mounts[link]; !ok {
continue
}
for _, entry := range mounts {
p := partition{
link,
mounts[link],
entry.Source,
entry.Mountpoint,
"",
entry.FSType,
0,
0,
0,
}
if value, ok := labels[link]; ok {
skip := false
for _, part := range partitions {
if part.Device == p.Device {
skip = true
}
}
if skip {
continue
}
if value, ok := labels[entry.Source]; ok {
p.Label = value
}
buf := new(syscall.Statfs_t)
err = syscall.Statfs(p.MountPoint, buf)
if err != nil {
log.Fatal(err)
continue
}
totalBlocks := buf.Blocks
freeBlocks := buf.Bfree
@@ -403,6 +403,78 @@ func getMountedPartitions() []partition {
return partitions
}
func GetInitSystem() string {
runCommand := func(command string) string {
cmd := exec.Command("/bin/bash", "-c", command)
workdir, err := os.Getwd()
if err != nil {
return ""
}
cmd.Dir = workdir
cmd.Env = os.Environ()
out, err := cmd.Output()
if err != nil {
return ""
}
return strings.TrimSpace(string(out))
}
process, err := ps.FindProcess(1)
if err != nil {
return ""
}
// Special cases
// OpenRC check
if _, err := os.Stat("/usr/sbin/openrc"); err == nil {
return "OpenRC " + runCommand("openrc --version | awk '{print $3}'")
}
// Default PID 1 process name checking
switch process.Executable() {
case "systemd":
return "Systemd " + runCommand("systemctl --version | head -n1 | awk '{print $2}'")
case "runit":
return "Runit"
case "dinit":
return "Dinit " + runCommand("dinit --version | head -n1 | awk '{print substr($3, 1, length($3)-1)}'")
case "enit":
return "Enit " + runCommand("enit --version | awk '{print $3}'")
default:
return process.Executable()
}
}
func GetLibc() string {
cmd := exec.Command("/bin/bash", "-c", "find /usr/lib64/ -maxdepth 1 -name 'ld-*' | grep musl")
if err := cmd.Run(); err != nil {
cmd = exec.Command("/bin/bash", "-c", "ldd --version | head -1 | cut -d' ' -f4")
bytes, err := cmd.Output()
if err != nil {
return "Glibc"
}
return "Glibc " + strings.TrimSpace(string(bytes))
}
cmd = exec.Command("/bin/bash", "-c", "ldd 2>&1 | grep 'Version' | cut -d' ' -f2")
bytes, err := cmd.Output()
if err != nil {
return "Musl"
}
return "Musl " + strings.TrimSpace(string(bytes))
}
func GetLocalIP() string {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
return ""
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP.String()
}
func FormatBytes(bytes uint64) string {
var suffixes [6]string
suffixes[0] = "B"