22 Commits
Author SHA1 Message Date
EnumDev c05f34eb7d Fixed minor bug and updated fetch_script.sh
Fixed bug which would cause partitions not to show up if /dev/disk/by-partlabel/ did not exist
Updated fetch_script.sh to use labels if available
2024-05-16 22:24:16 +03:00
EnumDev 39b901e6fd Added PARTITION<n>_LABEL bash variable 2024-05-16 22:05:03 +03:00
EnumDev 2af3ab1156 Close xdg connection after querying 2024-05-16 17:01:11 +03:00
EnumDev aba10e3e9e Updated README.md 2024-05-16 16:58:48 +03:00
EnumDev 0c376702c7 Added partition size support
Added MOUNTED_PARTITIONS bash variable
Added PARTITION<n>_DEVICE bash variable
Added PARTITION<n>_MOUNTPOINT bash variable
Added PARTITION<n>_TOTAL_SIZE bash variable
Added PARTITION<n>_USED_SIZE bash variable
Added PARTITION<n>_FREE_SIZE bash variable
2024-05-16 16:57:12 +03:00
EnumDev a5ffb4b32e Tidied up code
The fetch script environment is now mostly set up in each own function
2024-05-16 14:44:38 +03:00
EnumDev 4de0d34e28 Improved GPU and Screen resolution fetching
Replaced calls to bash for getting monitor resolutions
getGPUName() now returns the first GPU with available device information
2024-05-16 08:41:21 +03:00
EnumDev 7ed54ec1a5 DISPLAY_PROTOCOL Variable and separate monitor resolutions (On X11)
Added a DISPLAY_PROTOCOL variable
Resolution information has been converted to a Golang function and now lists different monitors separately
2024-05-15 16:37:09 +03:00
EnumDev 2984a7da5f Fixed chroot bugs and reduced executable size
Stormfetch will now only list CPU and memory information if available
Added 'ldflag "-w"' to go build which reduces file size
Added 'run' goal to Makefile
2024-05-15 13:25:11 +03:00
EnumDev 4a2833afff Shell information has been converted to a Golang function 2024-05-15 12:02:43 +03:00
EnumDev c13c730e4c Removed lshw as a dependency
Renamed Utils.go to utils.go
2024-05-15 10:07:20 +03:00
EnumDev 4c72295972 DE/WM information has been converted to a Golang function 2024-05-15 09:15:15 +03:00
EnumDev a29a8f1dd9 CPU, GPU and memory information have been converted to Golang functions 2024-05-14 10:03:18 +03:00
EnumDev 1fc9a9ea79 Added Bspwm support 2024-05-12 16:58:32 +03:00
EnumDev 01b23277fd Added gif to README.md
Changed README.md formatting
2024-05-12 11:24:58 +03:00
EnumDev 75deb165ad Updated configuration to support color 2024-05-12 10:14:00 +03:00
EnumDev 56511c90db Merge remote-tracking branch 'origin/master' 2024-05-11 21:18:10 +03:00
EnumDev 42a60296a9 Improved color support 2024-05-11 21:17:39 +03:00
EnumDev af4c534685 Merge branch 'master' into 'master'
Add AUR link and tidy up README grammar

See merge request CapCreeperGR/stormfetch!1
2024-05-11 17:31:13 +00:00
let 25a596cd5e tidy up the grammar a bit 2024-05-11 20:05:04 +03:00
let 4d414daccc add AUR to README 2024-05-11 20:03:08 +03:00
EnumDev 664b639fb9 Added color support 2024-05-11 19:16:53 +03:00
18 changed files with 741 additions and 294 deletions
+4 -1
View File
@@ -13,7 +13,7 @@ endif
build: build:
mkdir -p build mkdir -p build
$(GO) build -o build/stormfetch stormfetch $(GO) build -ldflags "-w" -o build/stormfetch stormfetch
install: build/stormfetch config/ install: build/stormfetch config/
mkdir -p $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(BINDIR)
@@ -29,5 +29,8 @@ compress: build/stormfetch config/
tar --owner=root --group=root -czf stormfetch.tar.gz stormfetch tar --owner=root --group=root -czf stormfetch.tar.gz stormfetch
rm -r stormfetch rm -r stormfetch
run: build/stormfetch
build/stormfetch
clean: clean:
rm -r build/ rm -r build/
+8 -5
View File
@@ -6,15 +6,18 @@
- [CapCreeperGR ](https://gitlab.com/CapCreeperGR) - [CapCreeperGR ](https://gitlab.com/CapCreeperGR)
### Project Information ### Project Information
Stormfetch is a program that can read your system's information and display it in the terminal along with ascii art of the linux distribution you are running. 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.
Stormfetch is still in beta and distro compatibility is limited. If you would like to contribute ascii art or add other compatibility features feel free to create a pull request or notify me through gitlab issues Stormfetch is still in beta, so distro compatibility is limited. If you would like to contribute ASCII art or add other compatibility features feel free to create a pull request or notify me through GitLab Issues.
### How it looks
![Stormfetch gif](media/stormfetch.gif)
### Installation Guide ### Installation Guide
#### Using a package manager
- Arch Linux: You may use your favorite AUR manager to install the `stormfetch` package
#### Building from source
- Download `go` from your package manager or from the go website - Download `go` from your package manager or from the go website
- Download `make` from your package manager - Download `make` from your package manager
- (Optional) Download `xorg-xhost` from your package manager to display DE/WM and monitor information
- (Optional) Download `xorg-xdpyinfo` from your package manager to display Screen Resolution
- (Optional) Download `lshw` from your package manager to display GPU information
- Run the following command to compile the project - Run the following command to compile the project
``` ```
make make
+5 -4
View File
@@ -1,4 +1,5 @@
-` #/4;27;4;11
${C1} -`
.o+` .o+`
`ooo/ `ooo/
`+oooo: `+oooo:
@@ -7,9 +8,9 @@
`/:-:++oooo+: `/:-:++oooo+:
`/++++/+++++++: `/++++/+++++++:
`/++++++++++++++: `/++++++++++++++:
`/+++ooooooooooooo/` `/+++o${C2}oooooooo${C1}oooo/`
./ooosssso++osssssso+` ${C2} ${C1}./${C2}ooosssso++osssssso${C1}+`
.oossssso-````/ossssss+` ${C2} .oossssso-````/ossssss+`
-osssssso. :ssssssso. -osssssso. :ssssssso.
:osssssss/ osssso+++. :osssssss/ osssso+++.
/ossssssss/ +ssssooo/- /ossssssss/ +ssssooo/-
+17 -16
View File
@@ -1,16 +1,17 @@
_,met$$$$$gg. #/1;7;9;15
,g$$$$$$$$$$$$$$$P. ${C2} _,met&&&&&gg.
,g$$P" """Y$$.". ,g&&&&&&&&&&&&&&&P.
,$$P' `$$$. ,g&&P" """Y&&.".
',$$P ,ggs. `$$b: ,&&P' `&&&.
`d$$' ,$P"' . $$$ ',&&P ,ggs. `&&b:
$$P d$' , $$P `d&&' ,&P"' ${C1}.${C2} &&&
$$: $$. - ,d$$' &&P d&' ${C1},${C2} &&P
$$; Y$b._ _,d$P' &&: &&. ${C1}-${C2} ,d&&'
Y$$. `.`"Y$$$$P"' &&; Y&b._ _,d&P'
`$$b "-.__ Y&&. ${C1}`.${C2}`"Y&&&&P"'
`Y$$ ${C2} `&&b ${C1}"-.__
`Y$$. ${C2} `Y&&
`$$b. `Y&&.
`Y$$b. `&&b.
`"Y$b._ `Y&&b.
`"Y&b._
+14 -13
View File
@@ -1,19 +1,20 @@
.',;::::;,'. #/12;7;4;15
${C1} .',;::::;,'.
.';:cccccccccccc:;,. .';:cccccccccccc:;,.
.;cccccccccccccccccccccc;. .;cccccccccccccccccccccc;.
.:cccccccccccccccccccccccccc:. .:cccccccccccccccccccccccccc:.
.;ccccccccccccc;.:dddl:.;ccccccc;. .;ccccccccccccc;${C2}.:dddl:.${C1};ccccccc;.
.:ccccccccccccc;OWMKOOXMWd;ccccccc:. .:ccccccccccccc;${C2}OWMKOOXMWd${C1};ccccccc:.
.:ccccccccccccc;KMMc;cc;xMMc;ccccccc:. .:ccccccccccccc;${C2}KMMc${C1};cc;${C2}xMMc${C1};ccccccc:.
,cccccccccccccc;MMM.;cc;;WW:;cccccccc, ,cccccccccccccc;${C2}MMM.${C1};cc;${C2};WW:${C1};cccccccc,
:cccccccccccccc;MMM.;cccccccccccccccc: :cccccccccccccc;${C2}MMM.${C1};cccccccccccccccc:
:ccccccc;oxOOOo;MMM0OOk.;cccccccccccc: :ccccccc;${C2}oxOOOo${C1};${C2}MMM0OOk.${C1};cccccccccccc:
cccccc;0MMKxdd:;MMMkddc.;cccccccccccc; cccccc;${C2}0MMKxdd:${C1};${C2}MMMkddc.${C1};cccccccccccc;
ccccc;XM0';cccc;MMM.;cccccccccccccccc' ccccc;${C2}XM0'${C1};cccc;${C2}MMM.${C1};cccccccccccccccc'
ccccc;MMo;ccccc;MMW.;ccccccccccccccc; ccccc;${C2}MMo${C1};ccccc;${C2}MMW.${C1};ccccccccccccccc;
ccccc;0MNc.ccc.xMMd;ccccccccccccccc; ccccc;${C2}0MNc.${C1}ccc${C2}.xMMd${C1};ccccccccccccccc;
cccccc;dNMWXXXWM0:;cccccccccccccc:, cccccc;${C2}dNMWXXXWM0:${C1};cccccccccccccc:,
cccccccc;.:odl:.;cccccccccccccc:,. cccccccc;${C2}.:odl:.${C1};cccccccccccccc:,.
:cccccccccccccccccccccccccccc:'. :cccccccccccccccccccccccccccc:'.
.:cccccccccccccccccccccc:;,.. .:cccccccccccccccccccccc:;,..
'::cccccccccccccc::;,. '::cccccccccccccc::;,.
+18 -17
View File
@@ -1,18 +1,19 @@
-/oyddmdhs+:. #/5;7;13;69
-odNMMMMMMMMNNmhy+-` ${C1} -/oyddmdhs+:.
-yNMMMMMMMMMMMNNNmmdhy+- -o${C2}dNMMMMMMMMNNmhy+${C1}-`
`omMMMMMMMMMMMMNmdmmmmddhhy/` -y${C2}NMMMMMMMMMMMNNNmmdhy${C1}+-
omMMMMMMMMMMMNhhyyyohmdddhhhdo` `o${C2}mMMMMMMMMMMMMNmdmmmmddhhy${C1}/`
.ydMMMMMMMMMMdhs++so/smdddhhhhdm+` om${C2}MMMMMMMMMMMN${C1}hhyyyo${C2}hmdddhhhd${C1}o`
oyhdmNMMMMMMMNdyooydmddddhhhhyhNd. .y${C2}dMMMMMMMMMMd${C1}hs++so/s${C2}mdddhhhhdm${C1}+`
:oyhhdNNMMMMMMMNNNmmdddhhhhhyymMh oy${C2}hdmNMMMMMMMN${C1}dyooy${C2}dmddddhhhhyhN${C1}d.
.:+sydNMMMMMNNNmmmdddhhhhhhmMmy :o${C2}yhhdNNMMMMMMMNNNmmdddhhhhhyym${C1}Mh
/mMMMMMMNNNmmmdddhhhhhmMNhs: .:${C2}+sydNMMMMMNNNmmmdddhhhhhhmM${C1}my
`oNMMMMMMMNNNmmmddddhhdmMNhs+` /m${C2}MMMMMMNNNmmmdddhhhhhmMNh${C1}s:
`sNMMMMMMMMNNNmmmdddddmNMmhs/. `o${C2}NMMMMMMMNNNmmmddddhhdmMNhs${C1}+`
/NMMMMMMMMNNNNmmmdddmNMNdso:` `s${C2}NMMMMMMMMNNNmmmdddddmNMmhs${C1}/.
+MMMMMMMNNNNNmmmmdmNMNdso/- /N${C2}MMMMMMMMNNNNmmmdddmNMNdso${C1}:`
yMMNNNNNNNmmmmmNNMmhs+/-` +M${C2}MMMMMMNNNNNmmmmdmNMNdso${C1}/-
/hMMNNNNNNNNMNdhs++/-` yM${C2}MNNNNNNNmmmmmNNMmhs+/${C1}-`
`/ohdmmddhys+++/:.` /h${C2}MMNNNNNNNNMNdhs++/${C1}-`
`/${C2}ohdmmddhys+++/:${C1}.`
`-//////:--. `-//////:--.
+13 -12
View File
@@ -1,17 +1,18 @@
.;ldkO0000Okdl;. #/2;7;10;15
${C2} .;ldkO0000Okdl;.
.;d00xl:^''''''^:ok00d;. .;d00xl:^''''''^:ok00d;.
.d00l' 'o00d. .d00l' 'o00d.
.d0Kd' Okxol:;,. :O0d. .d0Kd'${C1} Okxol:;,. ${C2}:O0d.
.OKKKK0kOKKKKKKKKKKOxo:, lKO. .OK${C1}KKK0kOKKKKKKKKKKOxo:, ${C2}lKO.
,0KKKKKKKKKKKKKKKK0P^,,,^dx: ;00, ,0K${C1}KKKKKKKKKKKKKKK0P^${C2},,,${C1}^dx:${C2} ;00,
.OKKKKKKKKKKKKKKKKk'.oOPPb.'0k. cKO. .OK${C1}KKKKKKKKKKKKKKKk'${C2}.oOPPb.${C1}'0k.${C2} cKO.
:KKKKKKKKKKKKKKKKK: kKx..dd lKd 'OK: :KK${C1}KKKKKKKKKKKKKKK: ${C2}kKx..dd ${C1}lKd${C2} 'OK:
dKKKKKKKKKKKOx0KKKd ^0KKKO' kKKc dKd dKK${C1}KKKKKKKKKOx0KKKd ${C2}^0KKKO' ${C1}kKKc${C2} dKd
dKKKKKKKKKKKK;.;oOKx,..^..;kKKK0. dKd dKK${C1}KKKKKKKKKK;.;oOKx,..${C2}^${C1}..;kKKK0.${C2} dKd
:KKKKKKKKKKKK0o;...^cdxxOK0O/^^' .0K: :KK${C1}KKKKKKKKKK0o;...^cdxxOK0O/^^' ${C2}.0K:
kKKKKKKKKKKKKKKK0x;,,......,;od lKk kKK${C1}KKKKKKKKKKKKK0x;,,......,;od ${C2}lKk
'0KKKKKKKKKKKKKKKKKKKKK00KKOo^ c00' '0K${C1}KKKKKKKKKKKKKKKKKKKK00KKOo^ ${C2}c00'
'kKKKOxddxkOO00000Okxoc;'' .dKk' 'kK${C1}KKOxddxkOO00000Okxoc;'' ${C2}.dKk'
l0Ko. .c00l' l0Ko. .c00l'
'l0Kk:. .;xK0l' 'l0Kk:. .;xK0l'
'lkK0xl:;,,,,;:ldO0kl' 'lkK0xl:;,,,,;:ldO0kl'
+2 -1
View File
@@ -1,4 +1,5 @@
...... #/2;7;10;15
${C1} ......
.,cdxxxoc,. .:kKMMMNWMMMNk:. .,cdxxxoc,. .:kKMMMNWMMMNk:.
cKMMN0OOOKWMMXo. ; ;0MWk:. .:OMMk. cKMMN0OOOKWMMXo. ; ;0MWk:. .:OMMk.
;WMK;. .lKMMNM, :NMK, .OMW; ;WMK;. .lKMMNM, :NMK, .OMW;
+2 -1
View File
@@ -1,4 +1,5 @@
@@@@@@@@@ #/6;10;5;12
${C1} @@@@@@@@@
@@@~~~~~~~~~@@ @@@~~~~~~~~~@@
@@~~~ ~~@ @@~~~ ~~@
@~~ @ @~~ @
+17 -16
View File
@@ -1,20 +1,21 @@
.-/+oossssoo+\-. #/1;7;3;15
${C1} .-/+oossssoo+\-.
´:+ssssssssssssssssss+:` ´:+ssssssssssssssssss+:`
-+ssssssssssssssssssyyssss+- -+ssssssssssssssssssyyssss+-
.ossssssssssssssssssdMMMNysssso. .ossssssssssssssssss${C2}dMMMNy${C1}sssso.
/ssssssssssshdmmNNmmyNMMMMhssssss\ /sssssssssss${C2}hdmmNNmmyNMMMMh${C1}ssssss\
+ssssssssshmydMMMMMMMNddddyssssssss+ +sssssssss${C2}hm${C1}yd${C2}MMMMMMMNddddy${C1}ssssssss+
/sssssssshNMMMyhhyyyyhmNMMMNhssssssss\ /ssssssss${C2}hNMMM${C1}yh${C2}hyyyyhmNMMMNh${C1}ssssssss\
.ssssssssdMMMNhsssssssssshNMMMdssssssss. .ssssssss${C2}dMMMNh${C1}ssssssssss${C2}hNMMMd${C1}ssssssss.
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ +ssss${C2}hhhyNMMNy${C1}ssssssssssss${C2}yNMMMy${C1}sssssss+
ossyNMMMNyMMhsssssssssssssshmmmhssssssso oss${C2}yNMMMNyMMh${C1}ssssssssssssss${C2}hmmmh${C1}ssssssso
ossyNMMMNyMMhsssssssssssssshmmmhssssssso oss${C2}yNMMMNyMMh${C1}sssssssssssssshmmmh${C1}ssssssso
+sssshhhyNMMNyssssssssssssyNMMMysssssss+ +ssss${C2}hhhyNMMNy${C1}ssssssssssss${C2}yNMMMy${C1}sssssss+
.ssssssssdMMMNhsssssssssshNMMMdssssssss. .ssssssss${C2}dMMMNh${C1}ssssssssss${C2}hNMMMd${C1}ssssssss.
\sssssssshNMMMyhhyyyyhdNMMMNhssssssss/ \ssssssss${C2}hNMMM${C1}yh${C2}hyyyyhdNMMMNh${C1}ssssssss/
+sssssssssdmydMMMMMMMMddddyssssssss+ +sssssssss${C2}dm${C1}yd${C2}MMMMMMMMddddy${C1}ssssssss+
\ssssssssssshdmNNNNmyNMMMMhssssss/ \sssssssssss${C2}hdmNNNNmyNMMMMh${C1}ssssss/
.ossssssssssssssssssdMMMNysssso. .ossssssssssssssssss${C2}dMMMNy${C1}sssso.
-+sssssssssssssssssyyyssss+- -+sssssssssssssssss${C2}yyy${C1}ssss+-
`:+ssssssssssssssssss+:` `:+ssssssssssssssssss+:`
.-\+oossssoo+/-. .-\+oossssoo+/-.
+2
View File
@@ -1,3 +1,5 @@
distro_ascii: auto distro_ascii: auto
fetch_script: auto fetch_script: auto
ansii_colors: []
force_config_ansii: false
dependency_warning: true dependency_warning: true
+26 -17
View File
@@ -1,21 +1,30 @@
source fetch_script_functions.sh source fetch_script_functions.sh
echo "Distribution: ${DISTRO_LONG_NAME} ($(uname -m))" echo -e "${C3}Distribution: ${C4}${DISTRO_LONG_NAME} ($(uname -m))"
echo "Hostname: $(cat /etc/hostname)" echo -e "${C3}Hostname: ${C4}$(cat /etc/hostname)"
echo "Kernel: $(uname -s) $(uname -r)" echo -e "${C3}Kernel: ${C4}$(uname -s) $(uname -r)"
echo "Packages: $(get_packages)" echo -e "${C3}Packages: ${C4}$(get_packages)"
echo "Shell: $(get_shell)" echo -e "${C3}Shell: ${C4}${USER_SHELL}"
echo "CPU: $(get_cpu_name) ($(nproc) threads)" if [ ! -z "$CPU_MODEL" ]; then echo -e "${C3}CPU: ${C4}${CPU_MODEL} (${CPU_THREADS} threads)"; fi
if command_exists lshw; then if [ ! -z "$GPU_MODEL" ]; then echo -e "${C3}GPU: ${C4}${GPU_MODEL}"; fi
echo "GPU: $(lshw -class display 2> /dev/null | grep 'product' | cut -d":" -f2 | xargs)" 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"
mountpoint="PARTITION${i}_MOUNTPOINT"
label="PARTITION${i}_LABEL"
total="PARTITION${i}_TOTAL_SIZE"
used="PARTITION${i}_USED_SIZE"
if [ -z "${!label}" ]; then
echo -e "${C3}Partition ${!mountpoint}: ${C4}${!used}/${!total}"
else
echo -e "${C3}Partition ${!label}: ${C4}${!used}/${!total}"
fi fi
echo "Memory: $(get_used_mem) MiB / $(get_total_mem) MiB" done
if xhost >& /dev/null ; then if [ ! -z "$DISPLAY_PROTOCOL" ]; then
if get_de_wm &> /dev/null; then echo -e "${C3}Display Protocol: ${C4}${DISPLAY_PROTOCOL}"
echo "DE/WM: $(get_de_wm)" for i in $(seq ${CONNECTED_MONITORS}); do
monitor="MONITOR$i"
echo -e "${C3}Screen $i: ${C4}${!monitor}"
done
fi fi
if command_exists xdpyinfo ; then if [ ! -z "$DE_WM" ]; then echo -e "${C3}DE/WM: ${C4}${DE_WM}"; fi
echo "Screen Resolution: $(get_screen_resolution)"
fi
fi
-71
View File
@@ -9,77 +9,6 @@ command_exists() {
fi fi
} }
get_shell() {
case ${SHELL##*/} in
"")
echo "Unknown"
;;
sh|ash|dash|es)
echo "${SHELL##*/} $(${SHELL##*/} --version)"
;;
bash)
echo "${SHELL##*/} $(${SHELL##*/} -c "echo "'$BASH_VERSION')"
;;
*)
SHELL_NAME=${SHELL##*/}
SHELL_VERSION="$($SHELL --version)"
SHELL_VERSION=${SHELL_VERSION//","}
SHELL_VERSION=${SHELL_VERSION//" "}
SHELL_VERSION=${SHELL_VERSION//"version"}
SHELL_VERSION=${SHELL_VERSION//"$SHELL_NAME"}
echo "$SHELL_NAME $SHELL_VERSION"
unset SHELL_NAME
unset SHELL_VERSION
;;
esac
}
get_cpu_name() {
grep -m1 "model name" /proc/cpuinfo | cut -d: -f2 | xargs
}
get_total_mem() {
free --mebi -t | grep 'Total' | tr -s ' ' | cut -d" " -f2
}
get_free_mem() {
free --mebi -t | grep 'Total' | tr -s ' ' | cut -d" " -f4
}
get_used_mem() {
free --mebi -t | grep 'Total' | tr -s ' ' | cut -d" " -f3
}
get_de_wm() {
if ps -e | grep "plasmashell" &> /dev/null ; then
echo "KDE Plasma $(plasmashell --version | awk '{print $2}')"
elif ps -e | grep "gnome-session" &> /dev/null ; then
echo "Gnome $(gnome-shell --version | awk '{print $3}')"
elif ps -e | grep "xfce4-session" &> /dev/null ; then
echo "XFCE $(xfce4-session --version | grep xfce4-session | awk '{print $2}')"
elif ps -e | grep "cinnamon" &> /dev/null ; then
echo "Cinnamon $(cinnamon --version | awk '{print $2}')"
elif ps -e | grep "mate-panel" &> /dev/null ; then
echo "Mate $(mate-about --version | awk '{print $4}')"
elif ps -e | grep "lxsession" &> /dev/null ; then
echo "LXDE"
elif ps -e | grep "sway" &> /dev/null ; then
echo "Sway $(sway --version | awk '{print $2}')"
elif ps -e | grep "icewm-session" &> /dev/null ; then
echo "IceWM $(icewm --version | awk '{print $2}' | sed 's/,//g')"
elif [ ! -z $DESKTOP_SESSION ]; then
echo "$DESKTOP_SESSION"
else
return 1
fi
}
get_screen_resolution() {
if xhost >& /dev/null && command_exists xdpyinfo; then
xdpyinfo | grep dimensions | tr -s ' ' | cut -d " " -f3
fi
}
get_packages() { get_packages() {
ARRAY=() ARRAY=()
if command_exists dpkg; then if command_exists dpkg; then
+15 -1
View File
@@ -2,4 +2,18 @@ module stormfetch
go 1.22 go 1.22
require gopkg.in/yaml.v3 v3.0.1 // indirect require (
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc
github.com/jackmordaunt/ghw v1.0.4
github.com/mitchellh/go-ps v1.0.0
gopkg.in/yaml.v3 v3.0.1
)
require (
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
golang.org/x/sys v0.3.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
+22
View File
@@ -1,3 +1,25 @@
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-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=
github.com/jackmordaunt/ghw v1.0.4/go.mod h1:4dReYvJ36CoAzIxlEx8du25Qi/YqKYvEGE9QJoRXiK8=
github.com/jackmordaunt/pcidb v1.0.1 h1:uLLZa6kD5P39r2cwMyJJkxmuHfH9Wq19gYQEbYcB0Z4=
github.com/jackmordaunt/pcidb v1.0.1/go.mod h1:OMmhrZOZVu2hYXhBDZXddypxwKR/dp4DbIgzCkQDxdQ=
github.com/jackmordaunt/wmi v1.2.4 h1:/XyuMiKby0qXNQp1j0uU0JqTWLM0QGOVok1Hf5Yagtg=
github.com/jackmordaunt/wmi v1.2.4/go.mod h1:K/+FH4467Vk2fJXhYQTZzhctkCMMR7PwHqKbnizFySo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
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=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+118 -114
View File
@@ -7,26 +7,30 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"regexp"
"strconv"
"strings" "strings"
) )
var configPath = "" var configPath = ""
var fetchScriptPath = "" var fetchScriptPath = ""
var config = StormfetchConfig{} var config = StormfetchConfig{
Ascii: "auto",
FetchScript: "auto",
AnsiiColors: make([]int, 0),
ForceConfigAnsii: false,
DependencyWarning: true,
}
type StormfetchConfig struct { type StormfetchConfig struct {
Ascii string `yaml:"distro_ascii"` Ascii string `yaml:"distro_ascii"`
FetchScript string `yaml:"fetch_script"` FetchScript string `yaml:"fetch_script"`
AnsiiColors []int `yaml:"ansii_colors"`
ForceConfigAnsii bool `yaml:"force_config_ansii"`
DependencyWarning bool `yaml:"dependency_warning"` DependencyWarning bool `yaml:"dependency_warning"`
} }
type DistroInfo struct {
ID string
LongName string
ShortName string
}
func main() { func main() {
readConfig() readConfig()
} }
@@ -70,7 +74,7 @@ func readConfig() {
} }
// Show Dependency warning if enabled // Show Dependency warning if enabled
if config.DependencyWarning { if config.DependencyWarning {
dependencies := []string{"lshw", "xhost", "xdpyinfo"} var dependencies []string
var missing []string var missing []string
for _, depend := range dependencies { for _, depend := range dependencies {
if _, err := os.Stat(path.Join("/usr/bin/", depend)); err != nil { if _, err := os.Stat(path.Join("/usr/bin/", depend)); err != nil {
@@ -85,137 +89,137 @@ func readConfig() {
fmt.Println("You can disable this warning through your stormfetch config") fmt.Println("You can disable this warning through your stormfetch config")
} }
} }
// Fetch ascii art and apply colors
colorMap := make(map[string]string)
colorMap["C0"] = "\033[0m"
setColorMap := func() {
for i := 0; i < 6; i++ {
if i > len(config.AnsiiColors)-1 {
colorMap["C"+strconv.Itoa(i+1)] = "\033[0m"
continue
}
colorMap["C"+strconv.Itoa(i+1)] = fmt.Sprintf("\033[1m\033[38;5;%dm", config.AnsiiColors[i])
}
}
setColorMap()
ascii := getDistroAsciiArt()
if strings.HasPrefix(ascii, "#/") {
firstLine := strings.Split(ascii, "\n")[0]
if !config.ForceConfigAnsii {
ansiiColors := strings.Split(strings.TrimPrefix(firstLine, "#/"), ";")
for i, color := range ansiiColors {
atoi, err := strconv.Atoi(color)
if err != nil {
log.Fatal(err)
}
if i < len(config.AnsiiColors) {
config.AnsiiColors[i] = atoi
} else {
config.AnsiiColors = append(config.AnsiiColors, atoi)
}
}
setColorMap()
}
ascii = os.Expand(ascii, func(s string) string {
return colorMap[s]
})
ascii = strings.TrimPrefix(ascii, firstLine+"\n")
} else {
ascii = os.Expand(ascii, func(s string) string {
return colorMap[s]
})
}
asciiSplit := strings.Split(ascii, "\n")
asciiNoColor := StripAnsii(ascii)
//Execute fetch script //Execute fetch script
cmd := exec.Command("/bin/bash", fetchScriptPath) cmd := exec.Command("/bin/bash", fetchScriptPath)
cmd.Dir = path.Dir(fetchScriptPath) cmd.Dir = path.Dir(fetchScriptPath)
cmd.Env = os.Environ() cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "DISTRO_LONG_NAME="+getDistroInfo().LongName) cmd.Env = append(cmd.Env, SetupFetchEnv()...)
cmd.Env = append(cmd.Env, "DISTRO_SHORT_NAME="+getDistroInfo().ShortName) 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() out, err := cmd.Output()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// Print Distro Information // Print Distro Information
ascii := getDistroAscii()
maxWidth := 0 maxWidth := 0
for _, line := range strings.Split(ascii, "\n") { for _, line := range strings.Split(asciiNoColor, "\n") {
if len(line) > maxWidth { if len(line) > maxWidth {
maxWidth = len(line) maxWidth = len(line)
} }
} }
for lineIndex, line := range strings.Split(ascii, "\n") { final := ""
for i := len(line); i < maxWidth+5; i++ { for lineIndex, line := range asciiSplit {
lineVisibleLength := len(strings.Split(asciiNoColor, "\n")[lineIndex])
lastAsciiColor := ""
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 + " " line = line + " "
} }
if lineIndex < len(strings.Split(string(out), "\n")) { asciiSplit[lineIndex] = lastAsciiColor + line
line = line + strings.Split(string(out), "\n")[lineIndex] str := string(out)
if lineIndex < len(strings.Split(str, "\n")) {
line = line + colorMap["C0"] + strings.Split(str, "\n")[lineIndex]
} }
fmt.Println(line) final += lastAsciiColor + line + "\n"
} }
fmt.Println(final)
} }
func readKeyValueFile(filepath string) (map[string]string, error) { func SetupFetchEnv() []string {
ret := make(map[string]string) var env = make(map[string]string)
if _, err := os.Stat(filepath); err != nil { env["DISTRO_LONG_NAME"] = getDistroInfo().LongName
return nil, err 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)
} }
bytes, err := os.ReadFile(filepath) partitions := getMountedPartitions()
if err != nil { if len(partitions) != 0 {
return nil, err 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
} }
str := string(bytes) env["PARTITION"+strconv.Itoa(i+1)+"_TOTAL_SIZE"] = FormatBytes(part.TotalSize)
lines := strings.Split(str, "\n") env["PARTITION"+strconv.Itoa(i+1)+"_USED_SIZE"] = FormatBytes(part.UsedSize)
for _, line := range lines { env["PARTITION"+strconv.Itoa(i+1)+"_FREE_SIZE"] = FormatBytes(part.FreeSize)
if len(strings.Split(line, "=")) >= 2 {
key := strings.SplitN(line, "=", 2)[0]
value := strings.SplitN(line, "=", 2)[1]
if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") {
value = value[1 : len(value)-1]
}
ret[key] = value
} }
} }
return ret, nil 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()
} }
func getDistroInfo() DistroInfo { var ret = make([]string, len(env))
distroID := "" i := 0
var releaseMap = make(map[string]string) for key, value := range env {
if _, err := os.Stat("/etc/os-release"); err == nil { ret[i] = fmt.Sprintf("%s=%s", key, value)
releaseMap, err = readKeyValueFile("/etc/os-release") i++
if err != nil {
return DistroInfo{
ID: "unknown",
LongName: "Unknown",
ShortName: "Unknown",
}
}
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,
}
}
}
}
return DistroInfo{
ID: "unknown",
LongName: "Unknown",
ShortName: "Unknown",
}
}
}
func getDistroAscii() string {
defaultAscii :=
` .--.
|o_o |
|:_/ |
// \ \
(| | )
/'\_ _/'\
\___)=(___/ `
var id string
if config.Ascii == "auto" {
id = getDistroInfo().ID
} else {
id = config.Ascii
}
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 != nil {
return defaultAscii
}
return string(bytes)
} else {
return defaultAscii
}
}
if _, err := os.Stat(path.Join(userConfDir, "stormfetch/ascii/", id)); err == nil {
bytes, err := os.ReadFile(path.Join(userConfDir, "stormfetch/ascii/", id))
if err != nil {
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))
if err != nil {
return defaultAscii
}
return string(bytes)
} else {
return defaultAscii
} }
return ret
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

+453
View File
@@ -0,0 +1,453 @@
package main
import (
"bufio"
"fmt"
"github.com/BurntSushi/xgb"
"github.com/BurntSushi/xgb/xinerama"
"github.com/jackmordaunt/ghw"
"github.com/mitchellh/go-ps"
"log"
"math"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"slices"
"strconv"
"strings"
"syscall"
)
type DistroInfo struct {
ID string
LongName string
ShortName string
}
func getDistroInfo() DistroInfo {
distroID := ""
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",
}
}
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,
}
}
}
}
return DistroInfo{
ID: "unknown",
LongName: "Unknown",
ShortName: "Unknown",
}
}
}
func getDistroAsciiArt() string {
defaultAscii :=
` .--.
|o_o |
|:_/ |
// \ \
(| | )
/'\_ _/'\
\___)=(___/ `
var id string
if config.Ascii == "auto" {
id = getDistroInfo().ID
} else {
id = config.Ascii
}
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 != nil {
return defaultAscii
}
return string(bytes)
} else {
return defaultAscii
}
}
if _, err := os.Stat(path.Join(userConfDir, "stormfetch/ascii/", id)); err == nil {
bytes, err := os.ReadFile(path.Join(userConfDir, "stormfetch/ascii/", id))
if err != nil {
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))
if err != nil {
return defaultAscii
}
return string(bytes)
} else {
return defaultAscii
}
}
func getCPUName() string {
cpu, err := ghw.CPU()
if err != nil {
return ""
}
if len(cpu.Processors) == 0 {
return ""
}
return cpu.Processors[0].Model
}
func getCPUThreads() int {
cpu, err := ghw.CPU()
if err != nil {
return 0
}
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
if err != nil {
return ""
}
for _, graphics := range gpu.GraphicsCards {
if graphics.DeviceInfo != nil {
return graphics.DeviceInfo.Product.Name
}
}
return ""
}
type Memory struct {
MemTotal int
MemFree int
MemAvailable int
}
func GetMemoryInfo() *Memory {
toInt := func(raw string) int {
if raw == "" {
return 0
}
res, err := strconv.Atoi(raw)
if err != nil {
panic(err)
}
return res
}
parseLine := func(raw string) (key string, value int) {
text := strings.ReplaceAll(raw[:len(raw)-2], " ", "")
keyValue := strings.Split(text, ":")
return keyValue[0], toInt(keyValue[1])
}
if _, err := os.Stat("/proc/meminfo"); err != nil {
return nil
}
file, err := os.Open("/proc/meminfo")
if err != nil {
panic(err)
}
defer file.Close()
bufio.NewScanner(file)
scanner := bufio.NewScanner(file)
res := Memory{}
for scanner.Scan() {
key, value := parseLine(scanner.Text())
switch key {
case "MemTotal":
res.MemTotal = value / 1024
case "MemFree":
res.MemFree = value / 1024
case "MemAvailable":
res.MemAvailable = value / 1024
}
}
return &res
}
func GetShell() 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))
}
file, err := os.ReadFile("/etc/passwd")
if err != nil {
return ""
}
str := string(file)
shell := ""
for _, line := range strings.Split(str, "\n") {
if strings.TrimSpace(line) == "" {
continue
}
userInfo := strings.Split(line, ":")
if userInfo[2] == strconv.Itoa(os.Getuid()) {
shell = userInfo[6]
}
}
shellName := filepath.Base(shell)
switch shellName {
case "dash":
return "Dash"
case "bash":
return "Bash " + runCommand("echo $BASH_VERSION")
case "zsh":
return "Zsh " + runCommand("$SHELL --version | awk '{print $2}'")
case "fish":
return "Fish " + runCommand("$SHELL --version | awk '{print $3}'")
default:
return "Unknown"
}
}
func GetDEWM() string {
processes, err := ps.Processes()
if err != nil {
log.Fatal(err)
}
var executables []string
for _, process := range processes {
executables = append(executables, process.Executable())
}
processExists := func(process string) bool {
return slices.Contains(executables, process)
}
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))
}
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}'")
} 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("sway") {
return "Sway " + runCommand("sway --version | awk '{print $3}'")
} else if processExists("bspwm") {
return "Bspwm " + runCommand("bspwm -v")
} else if processExists("icewm-session") {
return "IceWM " + runCommand("icewm --version | awk '{print $2}'")
}
return ""
}
func GetDisplayProtocol() string {
protocol := os.Getenv("XDG_SESSION_TYPE")
if protocol == "x11" {
return "X11"
} else if protocol == "wayland" {
return "Wayland"
}
return ""
}
func getMonitorResolution() []string {
var monitors []string
if GetDisplayProtocol() == "X11" {
conn, err := xgb.NewConn()
if err != nil {
return nil
}
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)))
}
}
return monitors
}
type partition struct {
Device string
MountPoint string
Label string
TotalSize uint64
UsedSize uint64
FreeSize uint64
}
func getMountedPartitions() []partition {
partuuids, err := os.ReadDir("/dev/disk/by-partuuid")
if err != nil {
return nil
}
partlabels, err := os.ReadDir("/dev/disk/by-partlabel")
if err != nil && !os.IsNotExist(err) {
return nil
}
labels := make(map[string]string)
for _, entry := range partlabels {
link, err := filepath.EvalSymlinks(filepath.Join("/dev/disk/by-partlabel/", entry.Name()))
if err != nil {
continue
}
labels[link] = entry.Name()
}
bytes, err := os.ReadFile("/proc/mounts")
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]
}
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
}
p := partition{
link,
mounts[link],
"",
0,
0,
0,
}
if value, ok := labels[link]; ok {
p.Label = value
}
buf := new(syscall.Statfs_t)
err = syscall.Statfs(p.MountPoint, buf)
if err != nil {
log.Fatal(err)
}
totalBlocks := buf.Blocks
freeBlocks := buf.Bfree
usedBlocks := totalBlocks - freeBlocks
blockSize := uint64(buf.Bsize)
p.TotalSize = totalBlocks * blockSize
p.FreeSize = freeBlocks * blockSize
p.UsedSize = usedBlocks * blockSize
partitions = append(partitions, p)
}
return partitions
}
func FormatBytes(bytes uint64) string {
var suffixes [6]string
suffixes[0] = "B"
suffixes[1] = "KiB"
suffixes[2] = "MiB"
suffixes[3] = "GiB"
suffixes[4] = "TiB"
suffixes[5] = "PiB"
bf := float64(bytes)
for _, unit := range suffixes {
if math.Abs(bf) < 1024.0 {
return fmt.Sprintf("%3.1f %s", bf, unit)
}
bf /= 1024.0
}
return fmt.Sprintf("%.1fYiB", bf)
}
func StripAnsii(str string) string {
const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
var re = regexp.MustCompile(ansi)
return re.ReplaceAllString(str, "")
}
func ReadKeyValueFile(filepath string) (map[string]string, error) {
ret := make(map[string]string)
if _, err := os.Stat(filepath); err != nil {
return nil, err
}
bytes, err := os.ReadFile(filepath)
if err != nil {
return nil, err
}
str := string(bytes)
lines := strings.Split(str, "\n")
for _, line := range lines {
if len(strings.Split(line, "=")) >= 2 {
key := strings.SplitN(line, "=", 2)[0]
value := strings.SplitN(line, "=", 2)[1]
if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") {
value = value[1 : len(value)-1]
}
ret[key] = value
}
}
return ret, nil
}