diff --git a/.github/tests/macos.sh b/.github/tests/macos.sh index 2de4784..6260fb7 100644 --- a/.github/tests/macos.sh +++ b/.github/tests/macos.sh @@ -12,11 +12,11 @@ errorOut () { bash_exe="/usr/local/bin/bash" -if [[ $(bash fetch --config sample.config.conf -v) ]]; then +if [[ $(bash fetch --config sample.config.conf --lib . -v) ]]; then successOut 'Fetched current output:' - ${bash_exe} fetch --config sample.config.conf -v + ${bash_exe} fetch --config sample.config.conf --lib . -v else errorOut 'fetch failed output:' - ${bash_exe} fetch --config sample.config.conf -v + ${bash_exe} fetch --config sample.config.conf --lib . -v exit 1 -fi \ No newline at end of file +fi diff --git a/.github/tests/ubuntu.sh b/.github/tests/ubuntu.sh index e94c457..406e42a 100644 --- a/.github/tests/ubuntu.sh +++ b/.github/tests/ubuntu.sh @@ -12,24 +12,21 @@ errorOut () { } -if [[ $(bash fetch --config sample.config.conf -v -C .) ]]; then +if [[ $(bash fetch --lib . --config sample.config.conf -v) ]]; then successOut 'Fetched current output:' - bash fetch --config sample.config.conf -C . -v + bash fetch --lib . --config sample.config.conf -v else errorOut 'fetch failed output:' - bash fetch --config sample.config.conf -C . -v + bash fetch --lib . --config sample.config.conf -v exit 1 fi -# shellcheck disable=SC1094 -source ./ascii/ubuntu.sh - n=0 IFS=$'\n' while read -r line; do _output[${n}]="${line}" ((n++)) -done <<< "$(bash fetch --config sample.config.conf -v -C .)" +done <<< "$(bash fetch --lib . --config sample.config.conf -v)" if [[ ! ${_output[0]} =~ ^(.*)'Finding kernel...found as'(.*)'Linux '[[:digit:]]+'.'[[:digit:]]+'.'[[:digit:]]+'-'[[:digit:]]+'-azure' ]]; then errorOut "!! Failed on kernel." diff --git a/.github/tests/windows.sh b/.github/tests/windows.sh index f64f2df..33dc898 100644 --- a/.github/tests/windows.sh +++ b/.github/tests/windows.sh @@ -10,21 +10,11 @@ errorOut () { printf '%b\n' "${error}${1}${reset}" } -if [[ $(type -p dos2unix) ]]; then - $(which dos2unix) fetch - $(which dos2unix) lib/Windows/ascii.sh -else - sed 's/\r$//' < fetch | od -c > fetch2.sh - mv fetch2.sh fetch - sed 's/\r$//' < lib/Windows/ascii.sh | od -c > lib/Windows/ascii2.sh - mv lib/Windows/ascii2.sh lib/Windows/ascii.sh -fi - -if [[ $(bash fetch --config sample.config.conf -v) ]]; then +if [[ $(bash fetch --config sample.config.conf --lib . -v) ]]; then successOut 'Fetched current output:' - bash fetch --config sample.config.conf -v + bash fetch --config sample.config.conf --lib . -v else errorOut 'fetch failed output:' - bash fetch --config sample.config.conf -v + bash fetch --config sample.config.conf --lib . -v exit 1 -fi \ No newline at end of file +fi diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f566335..624a554 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -21,11 +21,12 @@ jobs: - name: Create package structure run: | mkdir -p deb_pkg/usr/share/fetch + mldor -p deb_pkg/usr/share/man/man.1 mkdir -p deb_pkg/usr/local/bin cp -r ascii lib deb_pkg/usr/share/fetch/ - cp LICENSE README.md deb_pkg/usr/share/fetch/ - cp sample.config.conf deb_pkg/usr/share/fetch/config.conf + cp LICENSE README.md sample.config.conf deb_pkg/usr/share/fetch/ cp fetch deb_pkg/usr/local/bin/ + cp fetch.1 deb_pkg/usr/share/man/man.1/ - name: Build some variables to use run: | PVERSION=${{ env.CI_REF_NAME }} @@ -63,10 +64,11 @@ jobs: run: | mkdir -p rpm_pkg/usr/share/fetch mkdir -p rpm_pkg/usr/local/bin + mkdir -p rpm_pkg/usr/share/man/man.1 cp -r ascii lib rpm_pkg/usr/share/fetch/ - cp LICENSE README.md rpm_pkg/usr/share/fetch/ - cp sample.config.conf rpm_pkg/usr/share/fetch/config.conf + cp LICENSE README.md sample.config.conf rpm_pkg/usr/share/fetch/ cp fetch rpm_pkg/usr/local/bin/ + cp fetch.1 /usr/share/man/man.1/ - name: Build some variables to use run: | PVERSION=${{ env.CI_REF_NAME }} diff --git a/README.md b/README.md index b4c87e9..84f2d8f 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Over the past several years, I've received a couple of pretty repeatable complai - Totally unstandardeized use of brackets, quotes, braces, you name it. As mentioned, screenFetch was first started in 2009, when I was a senior in high school. I knew very little about BASH aside from small shell scripts and just using it as my shell. I continued to grow and maintain it over the next 10 years learning much along the way. However, I almost never revisited older sections of the script, resulting in totally different coding styles and inefficient information gathering in the older sections. fetch aims to solve that by hopefully keeping an easy to use coding standard throughout. - Monolithic, 15k line BASH script. While this was done to keep one of screenFetch's original core functionalities in place (the ability to `wget` the raw file, `chmod +x` to it, and run it as a one-liner), it has become a bear of a script to maintain, work on, and read. fetch aims to fix some of that, while breaking the aforementioned functionality, by splitting ASCII art and distribution/OS specific code into mostly separate, sourceable lib files. This will keep fetch very packageable and only as big as it needs to be to get all the information about your running system. - No persistent configuration / have to run every single time with tons of flags if you wanna do off the wall stuff. screenFetch had a couple of nice, interesting flags to alter the output of the script. However, if you wanted to do several modifications to the output, you had to either 1) alias the one-liner to something shorter or 2) remember all those flags and values every time you wanted to run it. fetch solves that by implementing a configuration file that is well commented and easy to follow. As fetch grows and I work in most of the screenFetch functionality, that configuration will grow to include many more configurable things. You should not have to do any major, huge editing to the configuration logic to include new functions and configuration sections, either. + ## License Components pulled from [screenFetch](https://github.com/KittyKatt/screenFetch) that were pulled in by external contributors are licensed under the GPLv3+ license. You can find this license at [LICENSE.gpl](LICENSE.gpl). diff --git a/fetch b/fetch index 3865667..c222f3a 100755 --- a/fetch +++ b/fetch @@ -1,11 +1,17 @@ #!/usr/bin/env bash # variables: script global +# script version FETCH_VERSION="0.8.1" +# directory where fetch library/ascii files live +# (configurable with -l/--lib) FETCH_DATA_DIR="/usr/share/fetch" +# default directory and filename where fetch config lives +# (config locdation configurable with --config/-c) FETCH_DATA_USER_DIR="${XDG_CONFIG_HOME:-${HOME}}/.config/fetch" FETCH_CONFIG_FILENAME="config" LC_ALL=C LANG=C + # https://github.com/KittyKatt/screenFetch/issues/549 if [[ ${OSTYPE} =~ linux || ${OSTYPE} == gnu ]]; then # issue seems to affect Ubuntu; add LSB directories if it appears on other distros too @@ -26,8 +32,7 @@ verboseOut() { esac } errorOut() { - printf '\033[1;37m[[ \033[1;31m! \033[1;37m]] \033[0m%s\n' "${1}" - exit 1 + printf '\033[1;37m[[ \033[1;31m! \033[1;37m]] \033[0m%b\n' "${1}" } # functions: text @@ -49,27 +54,6 @@ trim() { set +f } -# functions: configuration -fetchConfig() { - if [ -f "${1}" ]; then - while read -r line; do - if [[ ${line} =~ ^\[[[:alnum:]]+\] ]]; then - arrname="config_${line//[^[:alnum:]]/}" - declare -gA "${arrname}" - elif [[ ${line} =~ ^([_[:alpha:]][_[:alnum:]]*)"="(.*) ]]; then - # shellcheck disable=SC2086 - { - _arr=${arrname}[${BASH_REMATCH[1]}] - [ -z ${!_arr} ] && declare -g ${arrname}[${BASH_REMATCH[1]}]="${BASH_REMATCH[2]//\"/}" - unset _arr - } - fi - done < "${1}" - else - errorOut "No configuration file specified" - fi -} - # functions: color # variables: color reset='\e[0m' @@ -129,1309 +113,67 @@ getColor() { fi } -######################################### -# functions: detection -detect_kernel() { - IFS=" " read -ra kernel <<< "$(uname -srm)" - kernel_name="${kernel[0]}" - kernel_version="${kernel[1]}" - kernel_machine="${kernel[2]}" - - # pulled from neofetch source - if [ "${kernel_name}" == "Darwin" ]; then - # macOS can report incorrect versions unless this is 0. - # https://github.com/dylanaraps/neofetch/issues/1607 - export SYSTEM_VERSION_COMPAT=0 - - IFS=$'\n' read -d "" -ra sw_vers <<< "$(awk -F'<|>' '/key|string/ {print $3}' \ - "/System/Library/CoreServices/SystemVersion.plist")" - for ((i = 0; i < ${#sw_vers[@]}; i += 2)); do - case ${sw_vers[i]} in - ProductName) darwin_name=${sw_vers[i + 1]} ;; - ProductVersion) osx_version=${sw_vers[i + 1]} ;; - #ProductBuildVersion) osx_build=${sw_vers[i + 1]} ;; - *) : ;; - esac - done - fi - - # shellcheck disable=SC2154 - case ${config_kernel[short]} in - on) - my_kernel="${kernel_version}" - ;; - off) - my_kernel="${kernel_name} ${kernel_version}" - ;; - auto) - # shellcheck disable=SC2154 - if [[ ${config_global[short]} =~ 'on' ]]; then - my_kernel="${kernel_version}" - else - my_kernel="${kernel_name} ${kernel_version}" - fi - ;; - *) return ;; - esac - - verboseOut "Finding kernel...found as '${my_kernel}'." -} - -detect_os() { - case "${kernel_name}" in - Darwin) my_os=${darwin_name} ;; - SunOS) my_os=Solaris ;; - Haiku) my_os=Haiku ;; - MINIX) my_os=MINIX ;; - AIX) my_os=AIX ;; - IRIX*) my_os=IRIX ;; - FreeMiNT) my_os=FreeMiNT ;; - Linux | GNU*) - my_os=Linux - ;; - *BSD | DragonFly | Bitrig) - my_os=BSD - ;; - CYGWIN* | MSYS* | MINGW*) - my_os=Windows - ;; - *) - errorOut "Unknown OS detected, please report this issue." - ;; - esac - - verboseOut "Finding OS...found as '${my_os}'." -} - -detect_distro() { - if [ -z "${my_distro}" ]; then - local distro_detect= - my_distro="Unknown" - if [ "${my_os}" == "Linux" ] && [ "${my_distro}" == "Unknown" ]; then - # LSB Release Check - if type -p lsb_release > /dev/null 2>&1; then - distro_detect="$(lsb_release -si)" - distro_release="$(lsb_release -sr)" - distro_codename="$(lsb_release -sc)" - case ${distro_detect} in - "archlinux" | "Arch Linux" | "arch" | "Arch" | "archarm") - my_distro="Arch Linux" - unset distro_release - ;; - "ALDOS" | "Aldos") - my_distro="ALDOS" - ;; - "ArcoLinux") - my_distro="ArcoLinux" - unset distro_release - ;; - "artixlinux" | "Artix Linux" | "artix" | "Artix" | "Artix release") - my_distro="Artix" - ;; - "blackPantherOS" | "blackPanther" | "blackpanther" | "blackpantheros") - # shellcheck disable=SC2034,SC1091,SC2153 - { - my_distro=$( - source /etc/lsb-release - printf '%s' "${DISTRIB_ID}" - ) - distro_release=$( - source /etc/lsb-release - printf '%s' "${DISTRIB_RELEASE}" - ) - distro_codename=$( - source /etc/lsb-release - printf '%s' "${DISTRIB_CODENAME}" - ) - } - ;; - "Chakra") - my_distro="Chakra" - unset distro_release - ;; - "CentOSStream") - my_distro="CentOS Stream" - ;; - "BunsenLabs") - # shellcheck disable=SC2034,SC1091,SC2153 - { - my_distro=$( - source /etc/lsb-release - printf '%s' "${DISTRIB_ID}" - ) - distro_release=$( - source /etc/lsb-release - printf '%s' "${DISTRIB_RELEASE}" - ) - distro_codename=$( - source /etc/lsb-release - printf '%s' "${DISTRIB_CODENAME}" - ) - } - ;; - "Debian") - my_distro="Debian" - ;; - "Deepin") - my_distro="Deepin" - ;; - "elementary" | "elementary OS") - my_distro="elementary OS" - ;; - "EvolveOS") - my_distro="Evolve OS" - ;; - "Sulin") - my_distro="Sulin" - distro_release=$(awk -F'=' '/^ID_LIKE=/ {print $2}' /etc/os-release) - distro_codename="Roolling donkey" # this is not wrong :D - ;; - "KaOS" | "kaos") - my_distro="KaOS" - ;; - "frugalware") - my_distro="Frugalware" - unset distro_codename - unset distro_release - ;; - "Gentoo") - my_distro="Gentoo" - ;; - "Hyperbola GNU/Linux-libre" | "Hyperbola") - my_distro="Hyperbola GNU/Linux-libre" - unset distro_codename - unset distro_release - ;; - "Kali" | "Debian Kali Linux") - my_distro="Kali Linux" - if [[ ${distro_codename} =~ "kali-rolling" ]]; then - unset distro_codename - unset distro_release - fi - ;; - "Lunar Linux" | "lunar") - my_distro="Lunar Linux" - ;; - "ManjaroLinux") - my_distro="Manjaro" - ;; - "neon" | "KDE neon") - my_distro="KDE neon" - unset distro_codename - unset distro_release - ;; - "Ol" | "ol" | "Oracle Linux") - my_distro="Oracle Linux" - [ -f /etc/oracle-release ] && distro_release="$(sed 's/Oracle Linux //' /etc/oracle-release)" - ;; - "LinuxMint") - my_distro="Mint" - ;; - "openSUSE" | "openSUSE project" | "SUSE LINUX" | "SUSE" | *SUSELinuxEnterprise*) - my_distro="openSUSE" - ;; - "Parabola GNU/Linux-libre" | "Parabola") - my_distro="Parabola GNU/Linux-libre" - unset distro_codename - unset distro_release - ;; - "Parrot" | "Parrot Security") - my_distro="Parrot Security" - ;; - "PCLinuxOS") - my_distro="PCLinuxOS" - unset distro_codename - unset distro_release - ;; - "Peppermint") - my_distro="Peppermint" - unset distro_codename - ;; - "rhel" | *RedHatEnterprise*) - my_distro="Red Hat Enterprise Linux" - ;; - "RosaDesktopFresh") - my_distro="ROSA" - distro_release=$(grep 'VERSION=' /etc/os-release | cut -d ' ' -f3 | cut -d '"' -f1) - distro_codename=$(grep 'PRETTY_NAME=' /etc/os-release | cut -d ' ' -f4,4) - ;; - "SailfishOS") - my_distro="SailfishOS" - ;; - "Sparky" | "SparkyLinux") - my_distro="SparkyLinux" - ;; - "Ubuntu") - my_distro="Ubuntu" - ;; - "Void" | "VoidLinux") - my_distro="Void Linux" - unset distro_codename - unset distro_release - ;; - "Zorin") - my_distro="Zorin OS" - unset distro_codename - ;; - *) - my_distro="Unknown" - ;; - esac - fi - - # Existing File Check - # TODO: Lots of optimization with these if statements to do - if [ "${my_distro}" == "Unknown" ]; then - if [ -f "/etc/mcst_version" ]; then - my_distro="OS Elbrus" - distro_release="$(tail -n 1 /etc/mcst_version)" - if [ -n "${distro_release}" ]; then - distro_more="${distro_release}" - fi - fi - if [ -n "$(uname -o 2> /dev/null)" ]; then - os="$(uname -o)" - case ${os} in - "EndeavourOS") my_distro="EndeavourOS" ;; - "GNU/Linux") - if type -p crux > /dev/null 2>&1; then - my_distro="CRUX" - distro_more="$(crux | awk '{print $3}')" - fi - if type -p nixos-version > /dev/null 2>&1; then - my_distro="NixOS" - distro_more="$(nixos-version)" - fi - if type -p sorcery > /dev/null 2>&1; then - my_distro="SMGL" - fi - if (type -p guix && type -p herd) > /dev/null 2>&1; then - my_distro="Guix System" - fi - ;; - *) return ;; - esac - fi - - if [ "${my_distro}" == "Unknown" ]; then - if [ -f /etc/os-release ]; then - os_release="/etc/os-release" - elif [ -f /usr/lib/os-release ]; then - os_release="/usr/lib/os-release" - fi - if [ -n "${os_release}" ]; then - # shellcheck disable=SC2248 - distrib_id="$(< ${os_release})" - for l in ${distrib_id}; do - if [[ ${l} =~ ^ID= ]]; then - distrib_id=${l//*=/} - distrib_id=${distrib_id//\"/} - break 1 - fi - done - if [ -n "${distrib_id}" ]; then - if [ "${BASH_VERSINFO[0]}" -ge 4 ]; then - distrib_id=$(for d in ${distrib_id}; do printf '%s' "${d^} "; done) - my_distro=${distrib_id% } - unset distrib_id - else - distrib_id=$( - for d in ${distrib_id}; do - FIRST_LETTER=$(printf '%s' "${d:0:1}" | tr "[:lower:]" "[:upper:]") - printf '%s' "${FIRST_LETTER}${d:1} " - done - ) - my_distro=${distrib_id% } - unset distrib_id - fi - fi - - # Hotfixes - [ "${my_distro}" == "Opensuse-tumbleweed" ] && my_distro="openSUSE" && distro_more="Tumbleweed" - [ "${my_distro}" == "Opensuse-leap" ] && my_distro="openSUSE" - [ "${my_distro}" == "void" ] && my_distro="Void Linux" - [ "${my_distro}" == "evolveos" ] && my_distro="Evolve OS" - [ "${my_distro}" == "Sulin" ] && my_distro="Sulin" - [[ ${my_distro} == "Arch" || ${my_distro} == "Archarm" || ${my_distro} == "archarm" ]] && my_distro="Arch Linux" - [ "${my_distro}" == "elementary" ] && my_distro="elementary OS" - [[ ${my_distro} == "Fedora" && -d /etc/qubes-rpc ]] && my_distro="qubes" # Inner VM - [[ ${my_distro} == "Ol" || ${my_distro} == "ol" ]] && my_distro="Oracle Linux" - if [[ ${my_distro} == "Oracle Linux" && -f /etc/oracle-release ]]; then - distro_more="$(sed 's/Oracle Linux //' /etc/oracle-release)" - fi - # Upstream problem, SL and so EL is using rhel ID in os-release - if [ "${my_distro}" == "rhel" ] || [ "${my_distro}" == "Rhel" ]; then - my_distro="Red Hat Enterprise Linux" - if grep -q 'Scientific' /etc/os-release; then - my_distro="Scientific Linux" - elif grep -q 'EuroLinux' /etc/os-release; then - my_distro="EuroLinux" - fi - fi - - [ "${my_distro}" == "Neon" ] && my_distro="KDE neon" - [[ ${my_distro} == "SLED" || ${my_distro} == "sled" || ${my_distro} == "SLES" || ${my_distro} == "sles" ]] && my_distro="SUSE Linux Enterprise" - if [ "${my_distro}" == "SUSE Linux Enterprise" ] && [ -f /etc/os-release ]; then - distro_more="$(awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release | tr -d '"')" - fi - if [ "${my_distro}" == "Debian" ] && [ -f /usr/bin/pveversion ]; then - my_distro="Proxmox VE" - unset distro_codename - distro_release="$(/usr/bin/pveversion | grep -oP 'pve-manager\/\K\d+\.\d+')" - fi - fi - fi - - if [[ ${my_distro} == "Unknown" && ${OSTYPE} =~ "linux" && -f /etc/lsb-release ]]; then - LSB_RELEASE=$(< /etc/lsb-release) - my_distro=$(printf '%s' "${LSB_RELEASE}" | awk 'BEGIN { - distro = "Unknown" - } - { - if ($0 ~ /[Uu][Bb][Uu][Nn][Tt][Uu]/) { - distro = "Ubuntu" - exit - } - else if ($0 ~ /[Mm][Ii][Nn][Tt]/ && $0 ~ /[Dd][Ee][Bb][Ii][Aa][Nn]/) { - distro = "LMDE" - exit - } - else if ($0 ~ /[Mm][Ii][Nn][Tt]/) { - distro = "Mint" - exit - } - } END { - print distro - }') - fi - - if [ "${my_distro}" == "Unknown" ] && [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then - for di in arch chakra evolveos exherbo fedora \ - frugalware gentoo kogaion mageia obarun oracle pardus \ - pclinuxos redhat rosa SuSe; do - # shellcheck disable=SC2248 - if [ -f /etc/${di}-release ]; then - my_distro=${di} - break - fi - done - if [ "${my_distro}" == "oracle" ]; then - distro_more="$(sed 's/Oracle Linux //' /etc/oracle-release)" - elif [ "${my_distro}" == "SuSe" ]; then - my_distro="openSUSE" - if [ -f /etc/os-release ]; then - if grep -q -i 'SUSE Linux Enterprise' /etc/os-release; then - my_distro="SUSE Linux Enterprise" - distro_more=$(awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release | tr -d '"') - fi - fi - if [[ ${distro_more} =~ "Tumbleweed" ]]; then - distro_more="Tumbleweed" - fi - elif [ "${my_distro}" == "redhat" ]; then - grep -q -i 'CentOS' /etc/redhat-release && my_distro="CentOS" - grep -q -i 'Scientific' /etc/redhat-release && my_distro="Scientific Linux" - grep -q -i 'EuroLinux' /etc/redhat-release && my_distro="EuroLinux" - grep -q -i 'PCLinuxOS' /etc/redhat-release && my_distro="PCLinuxOS" - fi - fi - - if [ "${my_distro}" == "Unknown" ]; then - if [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then - if [ -f /etc/debian_version ]; then - if [ -f /etc/issue ]; then - if grep -q -i 'gNewSense' /etc/issue; then - my_distro="gNewSense" - elif grep -q -i 'KDE neon' /etc/issue; then - my_distro="KDE neon" - distro_more="$(cut -d ' ' -f3 /etc/issue)" - else - my_distro="Debian" - fi - fi - if grep -q -i 'Kali' /etc/debian_version; then - my_distro="Kali Linux" - fi - elif [ -f /etc/NIXOS ]; then - my_distro="NixOS" - elif [ -f /etc/dragora-version ]; then - my_distro="Dragora" - distro_more="$(cut -d, -f1 /etc/dragora-version)" - elif [ -f /etc/slackware-version ]; then - my_distro="Slackware" - elif [ -f /usr/share/doc/tc/release.txt ]; then - my_distro="TinyCore" - distro_more="$(cat /usr/share/doc/tc/release.txt)" - elif [ -f /etc/sabayon-edition ]; then - my_distro="Sabayon" - fi - fi - fi - - if [ "${my_distro}" == "Unknown" ] && [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then - if [ -f /etc/issue ]; then - my_distro=$(awk 'BEGIN { - distro = "Unknown" - } - { - if ($0 ~ /"Hyperbola GNU\/Linux-libre"/) { - distro = "Hyperbola GNU/Linux-libre" - exit - } - else if ($0 ~ /"Obarun"/) { - distro = "Obarun" - exit - } - else if ($0 ~ /"Parabola GNU\/Linux-libre"/) { - distro = "Parabola GNU/Linux-libre" - exit - } - else if ($0 ~ /"Solus"/) { - distro = "Solus" - exit - } - else if ($0 ~ /"ALDOS"/) { - distro = "ALDOS" - exit - } - } END { - print distro - }' /etc/issue) - fi - fi - - if [ "${my_distro}" == "Unknown" ] && [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then - if [ -f /etc/system-release ]; then - if grep -q -i 'Scientific Linux' /etc/system-release; then - my_distro="Scientific Linux" - elif grep -q -i 'Oracle Linux' /etc/system-release; then - my_distro="Oracle Linux" - fi - elif [ -f /etc/lsb-release ]; then - if grep -q -i 'CHROMEOS_RELEASE_NAME' /etc/lsb-release; then - my_distro="$(awk -F'=' '/^CHROMEOS_RELEASE_NAME=/ {print $2}' /etc/lsb-release)" - distro_more="$(awk -F'=' '/^CHROMEOS_RELEASE_VERSION=/ {print $2}' /etc/lsb-release)" - fi - fi - fi - fi - elif [ "${my_os}" == "Windows" ]; then - my_distro=$(wmic os get Caption) - my_distro=${my_distro/Caption/} - my_distro=$(trim "${my_distro/Microsoft /}") - my_distro=${my_distro%%+([[:space:]])} - [[ ${my_distro} =~ [[:space:]](.*) ]] && my_distro=${BASH_REMATCH[1]} - elif [[ ${my_os} =~ [Mm]ac ]]; then - case ${osx_version} in - 10.4*) my_distro="Mac OS X Tiger" ;; - 10.5*) my_distro="Mac OS X Leopard" ;; - 10.6*) my_distro="Mac OS X Snow Leopard" ;; - 10.7*) my_distro="Mac OS X Lion" ;; - 10.8*) my_distro="OS X Mountain Lion" ;; - 10.9*) my_distro="OS X Mavericks" ;; - 10.10*) my_distro="OS X Yosemite" ;; - 10.11*) my_distro="OS X El Capitan" ;; - 10.12*) my_distro="macOS Sierra" ;; - 10.13*) my_distro="macOS High Sierra" ;; - 10.14*) my_distro="macOS Mojave" ;; - 10.15*) my_distro="macOS Catalina" ;; - 10.16*) my_distro="macOS Big Sur" ;; - 11.0*) my_distro="macOS Big Sur" ;; - *) my_distro="macOS" ;; - esac - fi - fi - - # shellcheck disable=SC1090 - { - case ${my_distro,,} in - aldos) my_distro="ALDOS" ;; - alpine) my_distro="Alpine Linux" ;; - amzn | amazon | amazon*linux) my_distro="Amazon Linux" ;; - arch | arch*linux) my_distro="Arch Linux" ;; - arch32) - my_distro="Arch Linux 32" - [ -z "${ascii_distro}" ] && ascii_distro="Arch Linux" - ;; - arcolinux | arcolinux*) my_distro="ArcoLinux" ;; - artix | artix*linux) my_distro="Artix Linux" ;; - blackpantheros | black*panther*) my_distro="blackPanther OS" ;; - bunsenlabs) my_distro="BunsenLabs" ;; - centos) my_distro="CentOS" ;; - centos*stream) - my_distro="CentOS Stream" - [ -z "${ascii_distro}" ] && ascii_distro="CentOS" - ;; - chakra) my_distro="Chakra" ;; - chrome* | chromium*) my_distro="Chrome OS" ;; - crux) my_distro="CRUX" ;; - debian) - my_distro="Debian" - . ${FETCH_DATA_DIR}/lib/distro/debian/lib.sh - ;; - devuan) my_distro="Devuan" ;; - deepin) my_distro="Deepin" ;; - dragonflybsd) my_distro="DragonFlyBSD" ;; - dragora) my_distro="Dragora" ;; - drauger*) my_distro="DraugerOS" ;; - elementary | 'elementary os') my_distro="elementary OS" ;; - endeavour*) my_distro="EndeavourOS" ;; - eurolinux) my_distro="EuroLinux" ;; - evolveos) my_distro="Evolve OS" ;; - exherbo | exherbo*linux) my_distro="Exherbo" ;; - fedora) - my_distro="Fedora" - . ${FETCH_DATA_DIR}/lib/distro/fedora/lib.sh - ;; - freebsd) my_distro="FreeBSD" ;; - frugalware) my_distro="Frugalware" ;; - funtoo) my_distro="Funtoo" ;; - gentoo) - my_distro="Gentoo" - . ${FETCH_DATA_DIR}/lib/distro/gentoo/lib.sh - ;; - gnewsense) my_distro="gNewSense" ;; - guix*system) my_distro="Guix System" ;; - haiku) my_distro="Haiku" ;; - hyperbolagnu | hyperbolagnu/linux-libre | 'hyperbola gnu/linux-libre' | hyperbola) - my_distro="Hyperbola GNU/Linux-libre" - [ -z "${ascii_distro}" ] && ascii_distro="Hyperbola" - ;; - kali*linux) my_distro="Kali Linux" ;; - kaos) my_distro="KaOS" ;; - kde*neon | neon) - my_distro="KDE neon" - . ${FETCH_DATA_DIR}/lib/distro/kde-neon/lib.sh - ;; - kogaion) my_distro="Kogaion" ;; - lmde) my_distro="LMDE" ;; - lunar | lunar*linux) my_distro="Lunar Linux" ;; - *"macos"* | *"mac os x"*) - [ -z "${ascii_distro}" ] && ascii_distro="macOS" - ;; - manjaro) my_distro="Manjaro" ;; - mageia) my_distro="Mageia" ;; - mer) my_distro="Mer" ;; - mint | linux*mint) - my_distro="Mint" - . ${FETCH_DATA_DIR}/lib/distro/mint/lib.sh - ;; - netbsd) my_distro="NetBSD" ;; - netrunner) my_distro="Netrunner" ;; - nix | nix*os) my_distro="NixOS" ;; - obarun) my_distro="Obarun" ;; - ol | oracle*linux) my_distro="Oracle Linux" ;; - openbsd) my_distro="OpenBSD" ;; - os*elbrus) my_distro="OS Elbrus" ;; - parabolagnu | parabolagnu/linux-libre | 'parabola gnu/linux-libre' | parabola) - my_distro="Parabola GNU/Linux-libre" - [ -z "${ascii_distro}" ] && ascii_distro="Parabola" - ;; - parrot | parrot*security) my_distro="Parrot Security" ;; - pclinuxos | pclos) my_distro="PCLinuxOS" ;; - peppermint) my_distro="Peppermint" ;; - proxmox | proxmox*ve) my_distro="Proxmox VE" ;; - pureos) my_distro="PureOS" ;; - qubes) my_distro="Qubes OS" ;; - raspbian) my_distro="Raspbian" ;; - red*hat* | rhel) - my_distro="Red Hat Enterprise Linux" - [ -z "${ascii_distro}" ] && ascii_distro="RHEL" - ;; - rosa) my_distro="ROSA" ;; - sabayon) my_distro="Sabayon" ;; - sailfish | sailfish*os) - my_distro="SailfishOS" - . ${FETCH_DATA_DIR}/lib/distro/sailfish/lib.sh - ;; - scientific*) my_distro="Scientific Linux" ;; - siduction) my_distro="Siduction" ;; - smgl | source*mage | source*mage*gnu*linux) - my_distro="Source Mage GNU/Linux" - [ -z "${ascii_distro}" ] && ascii_distro="SourceMage" - ;; - solus) my_distro="Solus" ;; - sparky | sparky*linux) my_distro="SparkyLinux" ;; - steam | steam*os) my_distro="SteamOS" ;; - sulin) my_distro="Sulin" ;; - *suse*) - my_distro="openSUSE" - . ${FETCH_DATA_DIR}/lib/distro/suse/lib.sh - [ -z "${ascii_distro}" ] && ascii_distro="SUSE" - ;; - tinycore | tinycore*linux) my_distro="TinyCore" ;; - trisquel) my_distro="Trisquel" ;; - ubuntu) - my_distro="Ubuntu" - . ${FETCH_DATA_DIR}/lib/distro/ubuntu/lib.sh - ;; - void*linux) my_distro="Void Linux" ;; - *"windows"*) - [ -z "${ascii_distro}" ] && ascii_distro="Windows" - ;; - zorin*) my_distro="Zorin OS" ;; - *) - ascii_distro="Unknown" - config_ascii['colors']="random" - ;; - esac - } - - [ -z "${ascii_distro}" ] && ascii_distro="${my_distro}" - - [ -n "${ascii_distro}" ] && ascii_distro="${ascii_distro// /-}" +############################### +# functions: output +get_info() { + # Check for subtitle + local info info_subtitle path output + info="$(trim "${1}")" + info_subtitle="config_${1}[subtitle]" - if [ -f "${FETCH_DATA_DIR}/ascii/${ascii_distro,,}.sh" ]; then - # shellcheck source=/dev/null - . "${FETCH_DATA_DIR}/ascii/${ascii_distro,,}.sh" - else - # shellcheck disable=SC1094,SC1090 - . ${FETCH_DATA_DIR}/ascii/unknown.sh - fi + # Unset printed to start fresh + unset -v printed - # shellcheck disable=SC2154 - case ${config_distro[short]} in - on) - : - ;; - version) - [ -n "${distro_release}" ] && my_distro+=" ${distro_release}" - ;; - codename) - [ -n "${distro_codename}" ] && my_distro+=" ${distro_codename}" - ;; + # Store library file path to variable + path="${FETCH_DATA_DIR}/lib/detection/${info}.sh" - full) - [ -n "${distro_release}" ] && my_distro+=" ${distro_release}" - [ -n "${distro_codename}" ] && my_distro+=" ${distro_codename}" - ;; - auto | *) - # shellcheck disable=SC2154 - if [[ ${config_global[short]} =~ 'on' ]]; then - : - else - [ -n "${distro_release}" ] && my_distro+=" ${distro_release}" - [ -n "${distro_codename}" ] && my_distro+=" ${distro_codename}" - fi - ;; - esac + # Check if library file exists + if [ -f "${path}" ]; then + # source library file and run detection + # shellcheck disable=SC1090 + . "${path}" + "detect_${info}" - [[ ${config_distro[os_arch]} =~ 'on' ]] && my_distro+=" ${kernel_machine}" + # build variable name + infodisplay="my_${info}" - verboseOut "Finding distribution...found as '${my_distro}'." -} + # if print_info was called manually, break + [[ "${printed}" ]] && return -detect_userinfo() { - # shellcheck disable=SC2154 - if [ "${config_userinfo[display_user]}" == "on" ]; then - my_user=${USER} - if [ -z "${USER}" ]; then - my_user=$(whoami) - fi - my_userinfo="${my_user}" - fi + # Use shell expansion to trim function detection variable + output="$(trim "${!infodisplay}")" - # shellcheck disable=SC2154 - if [ "${config_userinfo[display_hostname]}" == "on" ]; then - my_host="${HOSTNAME}" - if [ "${my_distro}" == "Mac OS X" ] || [ "${my_distro}" == "macOS" ]; then - my_host=${my_host/.local/} - fi - if [ -n "${my_userinfo}" ]; then - my_userinfo="${my_userinfo}@${my_host}" + if [ -n "${!info_subtitle}" ]; then + print_info "${!info_subtitle}" "${output}" else - my_userinfo="${my_host}" + print_info "${output}" fi fi - - verboseOut "Finding user info...found as '${my_userinfo}'." -} - -detect_uptime() { - # get seconds up since boot - case ${my_os} in - "Mac OS X" | "macOS" | BSD) - boot=$(sysctl -n kern.boottime) - [[ ${boot} =~ [0-9]+ ]] && boot=${BASH_REMATCH[0]} - now=$(date +%s) - _seconds=$((now - boot)) - ;; - Linux | Windows | [G | g][N | n][U | u]) - if [ -f /proc/uptime ]; then - _seconds=$(< /proc/uptime) - _seconds=${_seconds//.*/} - else - boot=$(date -d"$(uptime -s)" +%s) - now=$(date +%s) - _seconds=$((now - boot)) - fi - ;; - Haiku) - _seconds=$(($(system_time) / 1000000)) - ;; - *) return ;; - esac - - # math! - _mins="$((_seconds / 60 % 60)) minutes" - _hours="$((_seconds / 3600 % 24)) hours" - _days="$((_seconds / 86400)) days" - - # get rid of plurals - ((${_mins/ */} == 1)) && _mins=${_mins/s/} - ((${_hours/ */} == 1)) && _hours=${_hours/s/} - ((${_days/ */} == 1)) && _days=${_days/s/} - - # don't output if field is empty - ((${_mins/ */} == 0)) && unset _mins - ((${_hours/ */} == 0)) && unset _hours - ((${_days/ */} == 0)) && unset _days - - # build the uptime line - my_uptime=${_days:+${_days}, }${_hours:+${_hours}, }${_mins} - my_uptime=${my_uptime%', '} - my_uptime=${my_uptime:-${_seconds} seconds} - - # shorthand - # shellcheck disable=SC2154 - case ${config_uptime[short]} in - on) - my_uptime=${my_uptime/ minutes/ mins} - my_uptime=${my_uptime/ minute/ min} - my_uptime=${my_uptime/ seconds/ secs} - ;; - tiny) - my_uptime=${my_uptime/ days/d} - my_uptime=${my_uptime/ day/d} - my_uptime=${my_uptime/ hours/h} - my_uptime=${my_uptime/ hour/h} - my_uptime=${my_uptime/ minutes/m} - my_uptime=${my_uptime/ minute/m} - my_uptime=${my_uptime/ seconds/s} - my_uptime=${my_uptime//,/} - ;; - off) - : - ;; - auto | *) - # shellcheck disable=SC2154 - if [ "${config_global[short]}" == 'on' ]; then - my_uptime=${my_uptime/ minutes/ mins} - my_uptime=${my_uptime/ minute/ min} - my_uptime=${my_uptime/ seconds/ secs} - fi - ;; - esac - - verboseOut "Finding current uptime...found as '${my_uptime}'." -} - -detect_packages() { - # most of this is pulled from neofetch with small edits to line up with - # previous screenfetch functionality - - # to adjust the number of pkgs per pkg manager - pkgs_h=0 - - # _has: Check if package manager installed. - # _dir: Count files or dirs in a glob. - # _pac: If packages > 0, log package manager name. - # _tot: Count lines in command output. - _has() { type -p "${1}" > /dev/null && manager=${1}; } - _dir() { - ((my_packages += $#)) - _pac "$(($# - pkgs_h))" - } - _pac() { - ((${1} > 0)) && { - managers+=("${1} (${manager})") - manager_string+="${manager}, " - } - } - _tot() { - IFS=$'\n' read -d "" -ra pkgs <<< "$("$@" 2> /dev/null)" - ((my_packages += ${#pkgs[@]})) - _pac "$((${#pkgs[@]} - pkgs_h))" - } - - # Redefine _tot() for Bedrock Linux. - [[ -f /bedrock/etc/bedrock-release && ${PATH} == */bedrock/cross/* ]] && { - _tot() { - IFS=$'\n' read -d "" -ra pkgs <<< "$(for s in $(brl list); do strat -r "${s}" "${@}"; done)" - ((my_packages += "${#pkgs[@]}")) - _pac "$((${#pkgs[@]} - pkgs_h))" - } - br_prefix="/bedrock/strata/*" - } - - # get total packages based on OS value - case ${my_os} in - Linux | BSD | Solaris) - # simple commands - _has kiss && _tot kiss 1 - _has cpt-list && _tot cpt-list - _has pacman-key && _tot pacman -Qq --color never - _has apt && _tot dpkg-query -W # dpkg-query is much faster than apt - _has rpm && _tot rpm -qa - _has xbps-query && _tot xbps-query -list - _has apk && _tot apk info - _has opkg && _tot opkg list-installed - _has pacman-g2 && _tot pacman-g2 -q - _has lvu && _tot lvu installed - _has tce-status && _tot tce-status -lvu - _has pkg_info && _tot pkg_info - _has tazpkg && pkgs_h=6 _tot tazpkg list && ((my_packages -= 6)) - _has sorcery && _tot gaze installed - _has alps && _tot alps showinstalled - _has butch && _tot butch list - _has swupd && _tot swupd bundle-list --quiet - _has pisi && _tot pisi list-installed - _has inary && _tot inary li - - # 'mine' conflicts with minesweeper games. - [[ -f /etc/SDE-VERSION ]] && _has mine && _tot mine -q - - # file/dir count - # $br_prefix is apparently fixed and won't change based on user input - # shellcheck disable=SC2086 - { - shopt -s nullglob - _has brew && _dir "$(brew --cellar)"/* - _has emerge && _dir ${br_prefix}/var/db/pkg/*/*/ - _has Compile && _dir ${br_prefix}/Programs/*/ - _has eopkg && _dir ${br_prefix}/var/lib/eopkg/package/* - _has crew && _dir ${br_prefix}/usr/local/etc/crew/meta/*.filelist - _has pkgtool && _dir ${br_prefix}/var/log/packages/* - _has scratch && _dir ${br_prefix}/var/lib/scratchpkg/index/*/.pkginfo - _has kagami && _dir ${br_prefix}/var/lib/kagami/pkgs/* - _has cave && _dir ${br_prefix}/var/db/paludis/repositories/cross-installed/*/data/*/ \ - ${br_prefix}/var/db/paludis/repositories/installed/data/*/ - shopt -u nullglob - } - - # Complex commands - _has kpm-pkg && ((my_packages += $(kpm --get-selections | grep -cv deinstall$))) - _has guix && { - manager=guix-system && _tot guix package -p "/run/current-system/profile" -I - manager=guix-user && _tot guix package -I - } - _has nix-store && { - nix-user-pkgs() { - nix-store -qR ~/.nix-profile - nix-store -qR /etc/profiles/per-user/"${USER}" - } - manager=nix-system && _tot nix-store -qR /run/current-system/sw - manager=nix-user && _tot nix-user-pkgs - manager=nix-default && _tot nix-store -qR /nix/var/nix/profiles/default - } - - # pkginfo is also the name of a python package manager which is painfully slow. - # TODO: Fix this somehow. (neofetch) - _has pkginfo && _tot pkginfo -i - - # BSD-like package detection - case ${kernel_name} in - FreeBSD | DragonFly) _has pkg && _tot pkg info ;; - *) - _has pkg && _dir /var/db/pkg/* - ((my_packages == 0)) && _has pkg && _tot pkg list - ;; - esac - - # list these last as they accompany regular package managers. - _has flatpak && _tot flatpak list - _has spm && _tot spm list -i - _has puyo && _dir ~/.puyo/installed - - # Snap hangs if the command is run without the daemon running. - # Only run snap if the daemon is also running. - _has snap && pgrep -x snapd > /dev/null && - pkgs_h=1 _tot snap list && ((my_packages -= 1)) - - # This is the only standard location for appimages. - # See: https://github.com/AppImage/AppImageKit/wiki - manager=appimage && _has appimaged && _dir ~/.local/bin/*.appimage - ;; - "Mac OS X" | "macOS") - _has port && pkgs_h=1 _tot port installed && ((my_packages -= 1)) - _has brew && _dir /usr/local/Cellar/* - _has nix-store && { - nix-user-pkgs() { - nix-store -qR ~/.nix-profile - nix-store -qR /etc/profiles/per-user/"${USER}" - } - manager=nix-system && _tot nix-store -qR /run/current-system/sw - manager=nix-user && _tot nix-store -qR nix-user-pkgs - } - ;; - Windows) - case ${kernel_name} in - CYGWIN*) _has cygcheck && _tot cygcheck -cd ;; - MSYS*) _has pacman && _tot pacman -Qq --color never ;; - *) : ;; - esac - - # Scoop environment throws errors if `tot scoop list` is used - _has scoop && pkgs_h=1 _dir ~/scoop/apps/* && ((my_packages -= 1)) - - # Count chocolatey packages. - _has choco && _dir /c/ProgramData/chocolatey/lib/* - [ -d /cygdrive/c/ProgramData/chocolatey/lib ] && - manager=choco _dir /cygdrive/c/ProgramData/chocolatey/lib/* - ;; - Haiku) - _has pkgman && _dir /boot/system/package-links/* - my_packages=${my_packages/pkgman/depot} - ;; - *) return ;; - esac - - if ((my_packages == 0)); then - unset my_packages - else - # shellcheck disable=SC2154 - case ${config_packages[managers]} in - off) - : - ;; - split) - printf -v my_packages '%s, ' "${managers[@]}" - my_packages=${my_packages%,*} - ;; - on | *) - my_packages+=" (${manager_string%,*})" - ;; - esac - # replace pacman-key with pacman - my_packages=${my_packages/pacman-key/pacman} - fi - - verboseOut "Finding current package count...found as '${my_packages}'." } +print_info() { + local info subtitle + info="${1}" -detect_shell() { - # get configuration on whether full shell path should be displayed - # shellcheck disable=SC2154 - case ${config_shell[path]} in - on) shell_type="${SHELL}" ;; - off | *) shell_type="${SHELL##*/}" ;; - esac - - # if version_info is off, then return what we have now - # shellcheck disable=SC2154 - [ "${config_shell[version]}" != "on" ] && my_shell="${shell_type}" && return - - # Possible Windows problem - [ "${my_os}" == "Windows" ] && shell_name="${shell_type//\.exe/}" - - # get shell versions - my_shell="${shell_name:=${shell_type}} " - - case ${shell_name:=${SHELL##*/}} in - bash) - # shellcheck disable=SC2016 - [ -n "${BASH_VERSION}" ] || BASH_VERSION=$("${SHELL}" -c 'printf %s "$BASH_VERSION"') - my_shell+="${BASH_VERSION/-*/}" - ;; - sh | ash | dash | es) ;; - *ksh) - # shellcheck disable=SC2154,SC2016 - my_shell+=$("${SHELL}" -c 'printf %s "$KSH_VERSION"') - my_shell=${my_shell/ * KSH/} - my_shell=${my_shell/version/} - ;; - osh) - # shellcheck disable=SC2016 - { - if [[ -n ${OIL_VERSION} ]]; then - my_shell+=${OIL_VERSION} - else - my_shell+=$("${SHELL}" -c 'printf %s "$OIL_VERSION"') - fi - } - ;; - tcsh) - # shellcheck disable=SC2016 - my_shell+=$("${SHELL}" -c 'printf %s "$tcsh"') - ;; - yash) - my_shell+=$("${SHELL}" --version 2>&1) - my_shell=${my_shell/ ${shell_name}/} - my_shell=${my_shell/ Yet another shell/} - my_shell=${my_shell/Copyright*/} - ;; - fish) - # shellcheck disable=SC2016 - [ -n "${FISH_VERSION}" ] || FISH_VERSION=$("${SHELL}" -c 'printf %s "$FISH_VERSION"') - my_shell+="${FISH_VERSION}" - ;; - *) - my_shell+=$("${SHELL}" --version 2>&1) - my_shell=${my_shell/ ${shell_name}/} - ;; - esac - - # remove unwanted - my_shell=${my_shell/, version/} - my_shell=${my_shell/xonsh\//xonsh } - my_shell=${my_shell/options*/} - my_shell=${my_shell/\(*\)/} - - verboseOut "Finding current shell...found as '${my_shell}'." -} - -detect_cpu() { - case ${my_os} in - "Mac OS X" | "macOS") - my_cpu="$(sysctl -n machdep.cpu.brand_string)" - _cores=$(sysctl -n hw.logicalcpu_max) - ;; - "Linux" | "Windows") - _file="/proc/cpuinfo" - case ${kernel_machine} in - "frv" | "hppa" | "m68k" | "openrisc" | "or"* | "powerpc" | "ppc"* | "sparc"*) - my_cpu="$(awk -F':' '/^cpu\t|^CPU/ {printf $2; exit}' "${_file}")" - ;; - "s390"*) - my_cpu="$(awk -F'=' '/machine/ {print $4; exit}' "${_file}")" - ;; - "ia64" | "m32r") - my_cpu="$(awk -F':' '/model/ {print $2; exit}' "${_file}")" - [ -z "${my_cpu}" ] && my_cpu="$(awk -F':' '/family/ {printf $2; exit}' "${_file}")" - ;; - *) - my_cpu="$(awk -F '\\s*: | @' \ - '/model name|Hardware|Processor|^cpu model|chip type|^cpu type/ { - cpu=$2; if ($1 == "Hardware") exit } END { print cpu }' "${_file}")" - ;; - esac - - _speed_dir="/sys/devices/system/cpu/cpu0/cpufreq" - - # Select the right temperature file. - [[ -d /sys/class/hwmon && -n "$(ls -A /sys/class/hwmon)" ]] && - for temp_dir in /sys/class/hwmon/*; do - if [ -n "${temp_dir}" ]; then - [[ "$(< "${temp_dir}/name")" =~ (cpu_thermal|coretemp|fam15h_power|k10temp) ]] && { - temp_dirs=("${temp_dir}"/temp*_input) - temp_dir=${temp_dirs[0]} - break - } - fi - done - - # Get CPU speed. - if [ -d "${_speed_dir}" ]; then - _speed="$(< "${_speed_dir}/bios_limit")" || - _speed="$(< "${_speed_dir}/scaling_max_freq")" || - _speed="$(< "${_speed_dir}/cpuinfo_max_freq")" - _speed="$((_speed / 1000))" - else - _speed="$(awk -F ': |\\.' '/cpu MHz|^clock/ {printf $2; exit}' "${_file}")" - _speed="${_speed/MHz/}" - fi - - # Get CPU temp. - [ -f "${temp_dir}" ] && _deg="$(($(< "${temp_dir}") * 100 / 10000))" - - # Get CPU cores. - _cores="$(grep -c "^processor" "${_file}")" - ;; - *) return ;; - esac - - # Remove un-needed patterns from cpu output. - my_cpu="${my_cpu//(TM)/}" - my_cpu="${my_cpu//(tm)/}" - my_cpu="${my_cpu//(R)/}" - my_cpu="${my_cpu//(r)/}" - my_cpu="${my_cpu//?([+[:space:]])CPU/}" - my_cpu="${my_cpu//Processor/}" - my_cpu="${my_cpu//Dual-Core/}" - my_cpu="${my_cpu//Quad-Core/}" - my_cpu="${my_cpu//Six-Core/}" - my_cpu="${my_cpu//Eight-Core/}" - my_cpu="${my_cpu//[1-9][0-9]-Core/}" - my_cpu="${my_cpu//[0-9]-Core/}" - my_cpu="${my_cpu//, * Compute Cores/}" - my_cpu="${my_cpu//Core / }" - my_cpu="${my_cpu//(\"AuthenticAMD\"*)/}" - my_cpu="${my_cpu//with Radeon * Graphics/}" - my_cpu="${my_cpu// with Radeon * Gfx/}" - my_cpu="${my_cpu//, altivec supported/}" - my_cpu="${my_cpu//FPU*/}" - my_cpu="${my_cpu//Chip Revision*/}" - my_cpu="${my_cpu//Technologies, Inc/}" - my_cpu="${my_cpu//Core2/Core 2}" - - # Trim spaces from core and speed output - _cores="${_cores//[[:space:]]/}" - _speed="${_speed//[[:space:]]/}" - - # Remove CPU brand from the output. - # shellcheck disable=SC2154 - if [ "${config_cpu[brand]}" == "off" ]; then - my_cpu="${my_cpu/AMD /}" - my_cpu="${my_cpu/Intel /}" - my_cpu="${my_cpu/Core? Duo /}" - my_cpu="${my_cpu/Qualcomm /}" - fi - - # Add CPU cores to the output. - # shellcheck disable=SC2154 - [[ ${config_cpu[cores]} != "off" && -n ${_cores} ]] && - case ${my_os} in - "Mac OS X" | "macOS") my_cpu="${my_cpu/@/(${_cores}) @}" ;; - *) my_cpu="${my_cpu} (${_cores})" ;; - esac - - # Add CPU speed to the output. - # shellcheck disable=SC2154 - if [[ ${config_cpu[speed]} != "off" && -n ${_speed} ]]; then - if ((_speed < 1000)); then - my_cpu="${my_cpu} @ ${_speed}MHz" - else - _speed="${_speed:0:1}.${_speed:1}" - my_cpu="${my_cpu} @ ${_speed}GHz" - fi + if [[ "${2}" ]]; then + subtitle="$(trim "${1}")" + info="${2}" fi - # Add CPU temp to the output. - # shellcheck disable=SC2154 - { - if [[ ${config_cpu[temp]} != "off" && -n ${_deg} ]]; then - _deg="${_deg//./}" - # Convert to Fahrenheit if enabled - [ "${config_cpu[temp]}" == "F" ] && _deg="$((_deg * 90 / 50 + 320))" - # Format the output - _deg="[${_deg/${_deg: -1}/}.${_deg: -1}°${config_cpu[temp]:-C}]" - my_cpu="${my_cpu} ${_deg}" - fi - } - - verboseOut "Finding CPU...found as '${my_cpu}'." -} - -detect_memory() { - case ${my_os} in - "Linux" | "Windows") - # MemUsed = Memtotal + Shmem - MemFree - Buffers - Cached - SReclaimable - # Source: https://github.com/KittyKatt/screenFetch/issues/386#issuecomment-249312716 - while IFS=":" read -r a b; do - case ${a} in - "MemTotal") - ((mem_used += ${b/kB/})) - mem_total="${b/kB/}" - ;; - "Shmem") ((mem_used += ${b/kB/})) ;; - "MemFree" | "Buffers" | "Cached" | "SReclaimable") - mem_used="$((mem_used -= ${b/kB/}))" - ;; - "MemAvailable") - mem_avail=${b/kB/} - ;; - esac - done < /proc/meminfo - - if [ -n "${mem_avail}" ]; then - mem_used=$(((mem_total - mem_avail) / 1024)) - else - mem_used="$((mem_used / 1024))" - fi - - mem_total="$((mem_total / 1024))" - ;; - "BSD") - case ${kernel_name} in - "NetBSD"*) mem_total="$(($(sysctl -n hw.physmem64) / 1024 / 1024))" ;; - *) mem_total="$(($(sysctl -n hw.physmem) / 1024 / 1024))" ;; - esac - - case ${kernel_name} in - "NetBSD"*) - mem_free="$(($(awk -F ':|kB' '/MemFree:/ {printf $2}' /proc/meminfo) / 1024))" - ;; - "FreeBSD"* | "DragonFly"*) - hw_pagesize="$(sysctl -n hw.pagesize)" - mem_inactive="$(($(sysctl -n vm.stats.vm.v_inactive_count) * hw_pagesize))" - mem_unused="$(($(sysctl -n vm.stats.vm.v_free_count) * hw_pagesize))" - mem_cache="$(($(sysctl -n vm.stats.vm.v_cache_count) * hw_pagesize))" - mem_free="$(((mem_inactive + mem_unused + mem_cache) / 1024 / 1024))" - ;; - "OpenBSD"*) ;; - *) mem_free="$(($(vmstat | awk 'END {printf $5}') / 1024))" ;; - esac - - case ${kernel_name} in - "OpenBSD"*) - mem_used="$(vmstat | awk 'END {printf $3}')" - mem_used="${mem_used/M/}" - ;; - *) mem_used="$((mem_total - mem_free))" ;; - esac - ;; - "Mac OS X" | "macOS") - mem_total="$(($(sysctl -n hw.memsize) / 1024 / 1024))" - mem_wired="$(vm_stat | awk '/ wired/ { print $4 }')" - mem_active="$(vm_stat | awk '/ active/ { printf $3 }')" - mem_compressed="$(vm_stat | awk '/ occupied/ { printf $5 }')" - mem_compressed="${mem_compressed:-0}" - mem_used="$(((${mem_wired//./} + ${mem_active//./} + ${mem_compressed//./}) * 4 / 1024))" - ;; - "Haiku") - mem_total="$(($(sysinfo -mem | awk -F '\\/ |)' '{print $2; exit}') / 1024 / 1024))" - mem_used="$(sysinfo -mem | awk -F '\\/|)' '{print $2; exit}')" - mem_used="$((${mem_used/max/} / 1024 / 1024))" - ;; - esac - - # shellcheck disable=SC2154 - [ "${config_memory[percent]}" == "on" ] && ((mem_perc = mem_used * 100 / mem_total)) - - my_memory="${mem_used}${mem_label:-MiB} / ${mem_total}${mem_label:-MiB} ${mem_perc:+(${mem_perc}%)}" - - verboseOut "Finding memory usage...found as '${my_memory}'." -} - -############################### -# functions: output -print_info() { - local _info="my_${1}" - local _infodisplay="my_${1}" - until [ -n "${!_info}" ]; do - ((${#_display} < 1)) && break - _display=("${_display[@]:1}") - _info="my_${1}}" - done - - if [ -n "${!_info}" ]; then - _info_subtitle="config_${1}[subtitle]" - if [ -n "${!_info_subtitle}" ]; then + if [ -n "${info}" ]; then + if [[ "${subtitle}" ]]; then # shellcheck disable=SC2154 - printf '%b\n' "${!_info_subtitle}${config_text[info_separator]} ${!_info}" + printf '%b\n' "${text_padding}${subtitle}${config_text[info_separator]} ${info}" else - printf '%b\n' "${!_info}" + printf '%b\n' "${text_padding}${info}" fi - else - : fi - _display=("${_display[@]:1}") + printed="1" + + ((info_height++)) } print_ascii() { local logo="${1}" - # shellcheck disable=SC2154 - gap=${config_ascii[gap]} - # Calculate: (max detected logo width - length of current line) - _tmp="${logo//\$\{??\}/}" - _tmp=${_tmp//\\\\/\\} - _tmp=${_tmp//█/ } - # shellcheck disable=SC2154 - if ((${#_tmp} < ascii_len)); then - logo_padding=$((ascii_len - ${#_tmp})) - else - logo_padding=0 - fi # Random coloring support if [ "${config_ascii['colors']}" == "random" ]; then @@ -1442,6 +184,7 @@ print_ascii() { logo="${logo//\$\{c${n}\}/${_randc}}" ((n++)) done + unset -v n fi # Expand color variables @@ -1454,34 +197,24 @@ print_ascii() { # Let's output! if [ "${config_text[display]}" == "on" ]; then + # shellcheck disable=SC2154 + gap=${config_ascii[gap]} + # Format line with gap after ASCII for info display - ((text_padding = logo_padding + gap)) - logo="$(printf "%b \e[%sC" "${logo}" "${text_padding}")" + ((text_padding = ascii_len + gap)) + text_padding="\e[${text_padding}C" + # logo="$(printf "%b \e[%sC" "${logo}" "${text_padding}")" # Display ASCII art and detected info # shellcheck disable=SC2154 - if [ "${i}" -lt "${startline}" ]; then - printf '%b\n' "${logo}${reset}" - elif [ "${i}" -ge "${startline}" ]; then - if ((${#_display} > 0)); then - _infodisplay="$(print_info "${_display[0]}")" - printf '%b\n' "${logo}${reset}${_infodisplay}" - _display=("${_display[@]:1}") - else - printf '%b\n' "${logo}${reset}" - fi - fi + printf '%b\n' "${logo}${reset}" # Cleanup # shellcheck disable=SC2031 unset _tmp - unset text_padding else printf '%b\n' "${logo}${reset}" fi - - # Cleanup - unset n } ############################# @@ -1496,23 +229,56 @@ versioninfo() { printf 'fetch %s\n' "${FETCH_VERSION}" } -main() { - detect_kernel - detect_os +############################### +# function: Cache uname +# cache uname output to not spawn more than one +# shellcheck disable=SC2034 +cache_uname() { + # Cache the output of uname so we don't + # have to spawn it multiple times. + IFS=" " read -ra uname <<< "$(uname -srm)" + + kernel_name="${uname[0]}" + kernel_version="${uname[1]}" + kernel_machine="${uname[2]}" + + if [[ "$kernel_name" == "Darwin" ]]; then + # macOS can report incorrect versions unless this is 0. + # https://github.com/dylanaraps/neofetch/issues/1607 + export SYSTEM_VERSION_COMPAT=0 + + IFS=$'\n' read -d "" -ra sw_vers <<< "$(awk -F'<|>' '/key|string/ {print $3}' \ + "/System/Library/CoreServices/SystemVersion.plist")" + for ((i=0;i<${#sw_vers[@]};i+=2)) { + case ${sw_vers[i]} in + ProductName) darwin_name=${sw_vers[i+1]} ;; + ProductVersion) osx_version=${sw_vers[i+1]} ;; + ProductBuildVersion) osx_build=${sw_vers[i+1]} ;; + esac + } + fi +} - # filter {config_global[info]} into a new variable, minus kernel because - # that is already detected above. keep old variable intact for output purposes. - GLOBAL_INFO="${config_global[info]//kernel /}" +main() { + # cache uname output to use later + cache_uname - for g in ${GLOBAL_INFO}; do - eval "detect_${g}" - done + # get simple info + # shellcheck disable=SC1090 + { + . "${FETCH_DATA_DIR}/lib/detection/os.sh" + . "${FETCH_DATA_DIR}/lib/detection/distro.sh" + } + detect_os + detect_distro - # shellcheck disable=SC2154 - read -r -a _display <<< "${config_global[info]}" + # TRAP script exit, unhide cursor + trap 'printf "\e[?25h\e[?7h"' EXIT + # hide cursor, disable line wrap + printf '\e[?25l\e[?7l' + # ascii display if [ "${config_ascii[display]}" == "on" ]; then - i=0 # Get logo max width # shellcheck disable=SC2154 while IFS=$'\n' read -r line; do @@ -1524,53 +290,83 @@ main() { # shellcheck disable=SC2154 while IFS=$'\n' read -r line; do print_ascii "${line}" - ((i++)) done <<< "${asciiLogo}" - unset i - else - while ((${#_display} > 0)); do - print_info "${_display[0]}" + + # reset cursor back to top to print info + printf '\e[%sA\e[9999999D' "${lines:-0}" + fi + + # info display + if [ "${config_text[display]}" == "on" ]; then + # shellcheck disable=SC2154 + [ "${config_ascii[display]}" == "on" ] && + until ((startline < 1)); do + printf '%b' '\n' + ((startline--)) + done + + IFS=" " read -ra display_array <<<"${config_global[info]}" + for g in "${display_array[@]}"; do + subtitle="config_${g}[subtitle]" + get_info "${g}" done + + [ "${config_ascii[display]}" == "on" ] && + # If the ascii art is taller than the info. + if ((lines > info_height)); then + lines=$((lines - info_height - startline)) + fi + + + printf -v nlines "%${lines}s" + printf "%b" "${nlines// /\\n}" fi } # Catch configuration flag -[[ $* != *--config* ]] && fetchConfig "${FETCH_DATA_USER_DIR}/${FETCH_CONFIG_FILENAME}" +[[ $* != *--config* ]] && FETCH_CONFIG="${FETCH_DATA_USER_DIR}/${FETCH_CONFIG_FILENAME}" # Execution flag detection -case ${1} in - --help) - usage - exit 0 - ;; - --version) - versioninfo - exit 0 - ;; - --config) - FETCH_CONFIG="${2}" - fetchConfig "${FETCH_CONFIG}" - shift 2 - ;; - *) : ;; -esac - -while getopts ":hvVNRTLD:A:C:" flags; do - # shellcheck disable=SC2154 - case ${flags} in - h) +while [[ $* =~ (--help|-h|--version|-V|--config|-c|--lib|-l) ]]; do + case ${1} in + --help | -h) usage exit 0 ;; - V) + --version | -V) versioninfo exit 0 ;; + --config | -c) + FETCH_CONFIG="${2}" + shift 2 + ;; + --lib | -l) + FETCH_DATA_DIR="${2}" + shift 2 + ;; + *) break ;; + esac +done + +if [ -f "${FETCH_DATA_DIR:-/usr/share/fetch}/lib/config.sh" ]; then + # shellcheck disable=SC1090 + . "${FETCH_DATA_DIR:-/usr/share/fetch}/lib/config.sh" +else + errorOut "Error: Could not find config.sh library in ${FETCH_DATA_DIR:-/usr/share/fetch}/lib/" + exit 1 +fi + +fetchConfig "${FETCH_CONFIG}" + +# shellcheck disable=SC2034 +while getopts ":hvVNRTLD:A:" flags; do + # shellcheck disable=SC2154 + case ${flags} in v) config_global[verbose]="on" ;; D) my_distro="${OPTARG}" ;; A) ascii_distro="${OPTARG}" ;; N) config_text[color]="off" ;; - C) FETCH_DATA_DIR="${OPTARG}" ;; T) config_ascii[display]="off" ;; L) config_text[display]="off" ;; R) config_ascii['colors']="random" ;; diff --git a/fetch.1 b/fetch.1 index 66e6d6d..d25fd19 100644 --- a/fetch.1 +++ b/fetch.1 @@ -46,6 +46,14 @@ Mac classic logo, and a custom Unknown distro cat art. .SH OPTIONS .TP +.B \--lib / -l /path/to/directory +Specify prefix path for fetch library files. The default +for this is /usr/share/fetch +.TP +.B \--config/ -c /path/to/file +Specify a configuratio file to use. The default for this is +~/.config/fetch/config +.TP .B \-v Verbose output. .TP @@ -61,6 +69,15 @@ Here you can specify the distribution art that you want displayed. This is for when you want your distro detected but want to display a different logo. .TP +.B \-T +Display text only output. +.TP +.B \-L +Display logo only output. +.TP +.B \-R +Display randomly colored logo output. +.TP .B \-V, \-\-version Display current script version. .TP @@ -81,4 +98,4 @@ Report bugs to .SH COPYRIGHT This is free software; you can redistribute it and/or modify it under -the terms of the MIT license. \ No newline at end of file +the terms of the MIT license. diff --git a/lib/config.sh b/lib/config.sh new file mode 100644 index 0000000..9a6ed44 --- /dev/null +++ b/lib/config.sh @@ -0,0 +1,38 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +fetchConfig() { + if [ -f "${1}" ]; then + while read -r line; do + if [[ ${line} =~ ^\[[[:alnum:]]+\] ]]; then + arrname="config_${line//[^[:alnum:]]/}" + declare -gA "${arrname}" + elif [[ ${line} =~ ^([_[:alpha:]][_[:alnum:]]*)"="(.*) ]]; then + # shellcheck disable=SC2086 + { + _arr=${arrname}[${BASH_REMATCH[1]}] + [ -z ${!_arr} ] && declare -g ${arrname}[${BASH_REMATCH[1]}]="${BASH_REMATCH[2]//\"/}" + unset _arr + } + fi + done < "${1}" + else + errorOut "No user configuration found, looking for sample config..." + if [ -f "${FETCH_DATA_DIR:-/usr/share/fetch}/sample.config.conf" ]; then + errorOut "Found sample configuration at ${FETCH_DATA_DIR:-/usr/share/fetch}/sample.config.conf. Copying to default path..." + cp "${FETCH_DATA_DIR:-/usr/share/fetch}/sample.config.conf" "${FETCH_DATA_USER_DIR}/${FETCH_CONFIG_FILENAME}" + if [ -f "${FETCH_DATA_USER_DIR}/${FETCH_CONFIG_FILENAME}" ]; then + errorOut "Copied configuration file to ${FETCH_DATA_USER_DIR}/${FETCH_CONFIG_FILENAME}" + errorOut "Please run fetch again." + exit 0 + else + errorOut "Failed to copy configuration. Please open a bug report at ${FETCH_SRC_LOCATION}" + exit 1 + fi + else + errorOut "Could not find sample configuration file...did you install fetch correctly?" + errorOut" Please consult ${FETCH_SRC_LOCATION} or your package manager for installation instructions." + exit 1 + fi + + fi +} diff --git a/lib/detection/cpu.sh b/lib/detection/cpu.sh new file mode 100644 index 0000000..5401796 --- /dev/null +++ b/lib/detection/cpu.sh @@ -0,0 +1,137 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_cpu() { + case ${my_os} in + "Mac OS X" | "macOS") + my_cpu="$(sysctl -n machdep.cpu.brand_string)" + _cores=$(sysctl -n hw.logicalcpu_max) + ;; + "Linux" | "Windows") + _file="/proc/cpuinfo" + case ${kernel_machine} in + "frv" | "hppa" | "m68k" | "openrisc" | "or"* | "powerpc" | "ppc"* | "sparc"*) + my_cpu="$(awk -F':' '/^cpu\t|^CPU/ {printf $2; exit}' "${_file}")" + ;; + "s390"*) + my_cpu="$(awk -F'=' '/machine/ {print $4; exit}' "${_file}")" + ;; + "ia64" | "m32r") + my_cpu="$(awk -F':' '/model/ {print $2; exit}' "${_file}")" + [ -z "${my_cpu}" ] && my_cpu="$(awk -F':' '/family/ {printf $2; exit}' "${_file}")" + ;; + *) + my_cpu="$(awk -F '\\s*: | @' \ + '/model name|Hardware|Processor|^cpu model|chip type|^cpu type/ { + cpu=$2; if ($1 == "Hardware") exit } END { print cpu }' "${_file}")" + ;; + esac + + _speed_dir="/sys/devices/system/cpu/cpu0/cpufreq" + + # Select the right temperature file. + [[ -d /sys/class/hwmon && -n "$(ls -A /sys/class/hwmon)" ]] && + for temp_dir in /sys/class/hwmon/*; do + if [ -n "${temp_dir}" ]; then + [[ "$(< "${temp_dir}/name")" =~ (cpu_thermal|coretemp|fam15h_power|k10temp) ]] && { + temp_dirs=("${temp_dir}"/temp*_input) + temp_dir=${temp_dirs[0]} + break + } + fi + done + + # Get CPU speed. + if [ -d "${_speed_dir}" ]; then + _speed="$(< "${_speed_dir}/bios_limit")" || + _speed="$(< "${_speed_dir}/scaling_max_freq")" || + _speed="$(< "${_speed_dir}/cpuinfo_max_freq")" + _speed="$((_speed / 1000))" + else + _speed="$(awk -F ': |\\.' '/cpu MHz|^clock/ {printf $2; exit}' "${_file}")" + _speed="${_speed/MHz/}" + fi + + # Get CPU temp. + [ -f "${temp_dir}" ] && _deg="$(($(< "${temp_dir}") * 100 / 10000))" + + # Get CPU cores. + _cores="$(grep -c "^processor" "${_file}")" + ;; + *) return ;; + esac + + # Remove un-needed patterns from cpu output. + my_cpu="${my_cpu//(TM)/}" + my_cpu="${my_cpu//(tm)/}" + my_cpu="${my_cpu//(R)/}" + my_cpu="${my_cpu//(r)/}" + my_cpu="${my_cpu//?([+[:space:]])CPU/}" + my_cpu="${my_cpu//Processor/}" + my_cpu="${my_cpu//Dual-Core/}" + my_cpu="${my_cpu//Quad-Core/}" + my_cpu="${my_cpu//Six-Core/}" + my_cpu="${my_cpu//Eight-Core/}" + my_cpu="${my_cpu//[1-9][0-9]-Core/}" + my_cpu="${my_cpu//[0-9]-Core/}" + my_cpu="${my_cpu//, * Compute Cores/}" + my_cpu="${my_cpu//Core / }" + my_cpu="${my_cpu//(\"AuthenticAMD\"*)/}" + my_cpu="${my_cpu//with Radeon * Graphics/}" + my_cpu="${my_cpu// with Radeon * Gfx/}" + my_cpu="${my_cpu//, altivec supported/}" + my_cpu="${my_cpu//FPU*/}" + my_cpu="${my_cpu//Chip Revision*/}" + my_cpu="${my_cpu//Technologies, Inc/}" + my_cpu="${my_cpu//Core2/Core 2}" + + # Trim spaces from core and speed output + _cores="${_cores//[[:space:]]/}" + _speed="${_speed//[[:space:]]/}" + + # Remove CPU brand from the output. + # shellcheck disable=SC2154 + if [ "${config_cpu[brand]}" == "off" ]; then + my_cpu="${my_cpu/AMD /}" + my_cpu="${my_cpu/Intel /}" + my_cpu="${my_cpu/Core? Duo /}" + my_cpu="${my_cpu/Qualcomm /}" + fi + + # Add CPU cores to the output. + # shellcheck disable=SC2154 + [[ ${config_cpu[cores]} != "off" && -n ${_cores} ]] && + case ${my_os} in + "Mac OS X" | "macOS") my_cpu="${my_cpu/@/(${_cores}) @}" ;; + *) my_cpu="${my_cpu} (${_cores})" ;; + esac + + # Add CPU speed to the output. + # shellcheck disable=SC2154 + if [[ ${config_cpu[speed]} != "off" && -n ${_speed} ]]; then + if ((_speed < 1000)); then + my_cpu="${my_cpu} @ ${_speed}MHz" + else + _speed="${_speed:0:1}.${_speed:1}" + my_cpu="${my_cpu} @ ${_speed}GHz" + fi + fi + + # Add CPU temp to the output. + # shellcheck disable=SC2154 + { + if [[ ${config_cpu[temp]} != "off" && -n ${_deg} ]]; then + _deg="${_deg//./}" + # Convert to Fahrenheit if enabled + [ "${config_cpu[temp]}" == "F" ] && _deg="$((_deg * 90 / 50 + 320))" + # Format the output + _deg="[${_deg/${_deg: -1}/}.${_deg: -1}°${config_cpu[temp]:-C}]" + my_cpu="${my_cpu} ${_deg}" + fi + } + + # Return my_cpu value for print_info() + #printf '%b' "$(trim "${my_cpu}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding CPU...found as '${my_cpu}'." +} diff --git a/lib/detection/distro.sh b/lib/detection/distro.sh new file mode 100644 index 0000000..0546cf6 --- /dev/null +++ b/lib/detection/distro.sh @@ -0,0 +1,624 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_distro() { + [[ "${my_distro}" ]] && return + + local distro_detect= + my_distro="Unknown" + if [ "${my_os}" == "Linux" ] && [ "${my_distro}" == "Unknown" ]; then + # LSB Release Check + if type -p lsb_release > /dev/null 2>&1; then + distro_detect="$(lsb_release -si)" + distro_release="$(lsb_release -sr)" + distro_codename="$(lsb_release -sc)" + case ${distro_detect} in + "archlinux" | "Arch Linux" | "arch" | "Arch" | "archarm") + my_distro="Arch Linux" + unset distro_release + ;; + "ALDOS" | "Aldos") + my_distro="ALDOS" + ;; + "ArcoLinux") + my_distro="ArcoLinux" + unset distro_release + ;; + "artixlinux" | "Artix Linux" | "artix" | "Artix" | "Artix release") + my_distro="Artix" + ;; + "blackPantherOS" | "blackPanther" | "blackpanther" | "blackpantheros") + # shellcheck disable=SC2034,SC1091,SC2153 + { + my_distro=$( + source /etc/lsb-release + printf '%s' "${DISTRIB_ID}" + ) + distro_release=$( + source /etc/lsb-release + printf '%s' "${DISTRIB_RELEASE}" + ) + distro_codename=$( + source /etc/lsb-release + printf '%s' "${DISTRIB_CODENAME}" + ) + } + ;; + "Chakra") + my_distro="Chakra" + unset distro_release + ;; + "CentOSStream") + my_distro="CentOS Stream" + ;; + "BunsenLabs") + # shellcheck disable=SC2034,SC1091,SC2153 + { + my_distro=$( + source /etc/lsb-release + printf '%s' "${DISTRIB_ID}" + ) + distro_release=$( + source /etc/lsb-release + printf '%s' "${DISTRIB_RELEASE}" + ) + distro_codename=$( + source /etc/lsb-release + printf '%s' "${DISTRIB_CODENAME}" + ) + } + ;; + "Debian") + my_distro="Debian" + ;; + "Deepin") + my_distro="Deepin" + ;; + "elementary" | "elementary OS") + my_distro="elementary OS" + ;; + "EvolveOS") + my_distro="Evolve OS" + ;; + "Sulin") + my_distro="Sulin" + distro_release=$(awk -F'=' '/^ID_LIKE=/ {print $2}' /etc/os-release) + distro_codename="Roolling donkey" # this is not wrong :D + ;; + "KaOS" | "kaos") + my_distro="KaOS" + ;; + "frugalware") + my_distro="Frugalware" + unset distro_codename + unset distro_release + ;; + "Gentoo") + my_distro="Gentoo" + ;; + "Hyperbola GNU/Linux-libre" | "Hyperbola") + my_distro="Hyperbola GNU/Linux-libre" + unset distro_codename + unset distro_release + ;; + "Kali" | "Debian Kali Linux") + my_distro="Kali Linux" + if [[ ${distro_codename} =~ "kali-rolling" ]]; then + unset distro_codename + unset distro_release + fi + ;; + "Lunar Linux" | "lunar") + my_distro="Lunar Linux" + ;; + "ManjaroLinux") + my_distro="Manjaro" + ;; + "neon" | "KDE neon") + my_distro="KDE neon" + unset distro_codename + unset distro_release + ;; + "Ol" | "ol" | "Oracle Linux") + my_distro="Oracle Linux" + [ -f /etc/oracle-release ] && distro_release="$(sed 's/Oracle Linux //' /etc/oracle-release)" + ;; + "LinuxMint") + my_distro="Mint" + ;; + "openSUSE" | "openSUSE project" | "SUSE LINUX" | "SUSE" | *SUSELinuxEnterprise*) + my_distro="openSUSE" + ;; + "Parabola GNU/Linux-libre" | "Parabola") + my_distro="Parabola GNU/Linux-libre" + unset distro_codename + unset distro_release + ;; + "Parrot" | "Parrot Security") + my_distro="Parrot Security" + ;; + "PCLinuxOS") + my_distro="PCLinuxOS" + unset distro_codename + unset distro_release + ;; + "Peppermint") + my_distro="Peppermint" + unset distro_codename + ;; + "rhel" | *RedHatEnterprise*) + my_distro="Red Hat Enterprise Linux" + ;; + "RosaDesktopFresh") + my_distro="ROSA" + distro_release=$(grep 'VERSION=' /etc/os-release | cut -d ' ' -f3 | cut -d '"' -f1) + distro_codename=$(grep 'PRETTY_NAME=' /etc/os-release | cut -d ' ' -f4,4) + ;; + "SailfishOS") + my_distro="SailfishOS" + ;; + "Sparky" | "SparkyLinux") + my_distro="SparkyLinux" + ;; + "Ubuntu") + my_distro="Ubuntu" + ;; + "Void" | "VoidLinux") + my_distro="Void Linux" + unset distro_codename + unset distro_release + ;; + "Zorin") + my_distro="Zorin OS" + unset distro_codename + ;; + *) + my_distro="Unknown" + ;; + esac + fi + + # Existing File Check + # TODO: Lots of optimization with these if statements to do + if [ "${my_distro}" == "Unknown" ]; then + if [ -f "/etc/mcst_version" ]; then + my_distro="OS Elbrus" + distro_release="$(tail -n 1 /etc/mcst_version)" + if [ -n "${distro_release}" ]; then + distro_more="${distro_release}" + fi + fi + if [ -n "$(uname -o 2> /dev/null)" ]; then + os="$(uname -o)" + case ${os} in + "EndeavourOS") my_distro="EndeavourOS" ;; + "GNU/Linux") + if type -p crux > /dev/null 2>&1; then + my_distro="CRUX" + distro_more="$(crux | awk '{print $3}')" + fi + if type -p nixos-version > /dev/null 2>&1; then + my_distro="NixOS" + distro_more="$(nixos-version)" + fi + if type -p sorcery > /dev/null 2>&1; then + my_distro="SMGL" + fi + if (type -p guix && type -p herd) > /dev/null 2>&1; then + my_distro="Guix System" + fi + ;; + *) return ;; + esac + fi + + if [ "${my_distro}" == "Unknown" ]; then + if [ -f /etc/os-release ]; then + os_release="/etc/os-release" + elif [ -f /usr/lib/os-release ]; then + os_release="/usr/lib/os-release" + fi + if [ -n "${os_release}" ]; then + # shellcheck disable=SC2248 + distrib_id="$(< ${os_release})" + for l in ${distrib_id}; do + if [[ ${l} =~ ^ID= ]]; then + distrib_id=${l//*=/} + distrib_id=${distrib_id//\"/} + break 1 + fi + done + if [ -n "${distrib_id}" ]; then + if [ "${BASH_VERSINFO[0]}" -ge 4 ]; then + distrib_id=$(for d in ${distrib_id}; do printf '%s' "${d^} "; done) + my_distro=${distrib_id% } + unset distrib_id + else + distrib_id=$( + for d in ${distrib_id}; do + FIRST_LETTER=$(printf '%s' "${d:0:1}" | tr "[:lower:]" "[:upper:]") + printf '%s' "${FIRST_LETTER}${d:1} " + done + ) + my_distro=${distrib_id% } + unset distrib_id + fi + fi + + # Hotfixes + [ "${my_distro}" == "Opensuse-tumbleweed" ] && my_distro="openSUSE" && distro_more="Tumbleweed" + [ "${my_distro}" == "Opensuse-leap" ] && my_distro="openSUSE" + [ "${my_distro}" == "void" ] && my_distro="Void Linux" + [ "${my_distro}" == "evolveos" ] && my_distro="Evolve OS" + [ "${my_distro}" == "Sulin" ] && my_distro="Sulin" + [[ ${my_distro} == "Arch" || ${my_distro} == "Archarm" || ${my_distro} == "archarm" ]] && my_distro="Arch Linux" + [ "${my_distro}" == "elementary" ] && my_distro="elementary OS" + [[ ${my_distro} == "Fedora" && -d /etc/qubes-rpc ]] && my_distro="qubes" # Inner VM + [[ ${my_distro} == "Ol" || ${my_distro} == "ol" ]] && my_distro="Oracle Linux" + if [[ ${my_distro} == "Oracle Linux" && -f /etc/oracle-release ]]; then + distro_more="$(sed 's/Oracle Linux //' /etc/oracle-release)" + fi + # Upstream problem, SL and so EL is using rhel ID in os-release + if [ "${my_distro}" == "rhel" ] || [ "${my_distro}" == "Rhel" ]; then + my_distro="Red Hat Enterprise Linux" + if grep -q 'Scientific' /etc/os-release; then + my_distro="Scientific Linux" + elif grep -q 'EuroLinux' /etc/os-release; then + my_distro="EuroLinux" + fi + fi + + [ "${my_distro}" == "Neon" ] && my_distro="KDE neon" + [[ ${my_distro} == "SLED" || ${my_distro} == "sled" || ${my_distro} == "SLES" || ${my_distro} == "sles" ]] && my_distro="SUSE Linux Enterprise" + if [ "${my_distro}" == "SUSE Linux Enterprise" ] && [ -f /etc/os-release ]; then + distro_more="$(awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release | tr -d '"')" + fi + if [ "${my_distro}" == "Debian" ] && [ -f /usr/bin/pveversion ]; then + my_distro="Proxmox VE" + unset distro_codename + distro_release="$(/usr/bin/pveversion | grep -oP 'pve-manager\/\K\d+\.\d+')" + fi + fi + fi + + if [[ ${my_distro} == "Unknown" && ${OSTYPE} =~ "linux" && -f /etc/lsb-release ]]; then + LSB_RELEASE=$(< /etc/lsb-release) + my_distro=$(printf '%s' "${LSB_RELEASE}" | awk 'BEGIN { + distro = "Unknown" + } + { + if ($0 ~ /[Uu][Bb][Uu][Nn][Tt][Uu]/) { + distro = "Ubuntu" + exit + } + else if ($0 ~ /[Mm][Ii][Nn][Tt]/ && $0 ~ /[Dd][Ee][Bb][Ii][Aa][Nn]/) { + distro = "LMDE" + exit + } + else if ($0 ~ /[Mm][Ii][Nn][Tt]/) { + distro = "Mint" + exit + } + } END { + print distro + }') + fi + + if [ "${my_distro}" == "Unknown" ] && [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then + for di in arch chakra evolveos exherbo fedora \ + frugalware gentoo kogaion mageia obarun oracle pardus \ + pclinuxos redhat rosa SuSe; do + # shellcheck disable=SC2248 + if [ -f /etc/${di}-release ]; then + my_distro=${di} + break + fi + done + if [ "${my_distro}" == "oracle" ]; then + distro_more="$(sed 's/Oracle Linux //' /etc/oracle-release)" + elif [ "${my_distro}" == "SuSe" ]; then + my_distro="openSUSE" + if [ -f /etc/os-release ]; then + if grep -q -i 'SUSE Linux Enterprise' /etc/os-release; then + my_distro="SUSE Linux Enterprise" + distro_more=$(awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release | tr -d '"') + fi + fi + if [[ ${distro_more} =~ "Tumbleweed" ]]; then + distro_more="Tumbleweed" + fi + elif [ "${my_distro}" == "redhat" ]; then + grep -q -i 'CentOS' /etc/redhat-release && my_distro="CentOS" + grep -q -i 'Scientific' /etc/redhat-release && my_distro="Scientific Linux" + grep -q -i 'EuroLinux' /etc/redhat-release && my_distro="EuroLinux" + grep -q -i 'PCLinuxOS' /etc/redhat-release && my_distro="PCLinuxOS" + fi + fi + + if [ "${my_distro}" == "Unknown" ]; then + if [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then + if [ -f /etc/debian_version ]; then + if [ -f /etc/issue ]; then + if grep -q -i 'gNewSense' /etc/issue; then + my_distro="gNewSense" + elif grep -q -i 'KDE neon' /etc/issue; then + my_distro="KDE neon" + distro_more="$(cut -d ' ' -f3 /etc/issue)" + else + my_distro="Debian" + fi + fi + if grep -q -i 'Kali' /etc/debian_version; then + my_distro="Kali Linux" + fi + elif [ -f /etc/NIXOS ]; then + my_distro="NixOS" + elif [ -f /etc/dragora-version ]; then + my_distro="Dragora" + distro_more="$(cut -d, -f1 /etc/dragora-version)" + elif [ -f /etc/slackware-version ]; then + my_distro="Slackware" + elif [ -f /usr/share/doc/tc/release.txt ]; then + my_distro="TinyCore" + distro_more="$(cat /usr/share/doc/tc/release.txt)" + elif [ -f /etc/sabayon-edition ]; then + my_distro="Sabayon" + fi + fi + fi + + if [ "${my_distro}" == "Unknown" ] && [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then + if [ -f /etc/issue ]; then + my_distro=$(awk 'BEGIN { + distro = "Unknown" + } + { + if ($0 ~ /"Hyperbola GNU\/Linux-libre"/) { + distro = "Hyperbola GNU/Linux-libre" + exit + } + else if ($0 ~ /"Obarun"/) { + distro = "Obarun" + exit + } + else if ($0 ~ /"Parabola GNU\/Linux-libre"/) { + distro = "Parabola GNU/Linux-libre" + exit + } + else if ($0 ~ /"Solus"/) { + distro = "Solus" + exit + } + else if ($0 ~ /"ALDOS"/) { + distro = "ALDOS" + exit + } + } END { + print distro + }' /etc/issue) + fi + fi + + if [ "${my_distro}" == "Unknown" ] && [[ ${OSTYPE} =~ "linux" || ${OSTYPE} == "gnu" ]]; then + if [ -f /etc/system-release ]; then + if grep -q -i 'Scientific Linux' /etc/system-release; then + my_distro="Scientific Linux" + elif grep -q -i 'Oracle Linux' /etc/system-release; then + my_distro="Oracle Linux" + fi + elif [ -f /etc/lsb-release ]; then + if grep -q -i 'CHROMEOS_RELEASE_NAME' /etc/lsb-release; then + my_distro="$(awk -F'=' '/^CHROMEOS_RELEASE_NAME=/ {print $2}' /etc/lsb-release)" + distro_more="$(awk -F'=' '/^CHROMEOS_RELEASE_VERSION=/ {print $2}' /etc/lsb-release)" + fi + fi + fi + fi + elif [ "${my_os}" == "Windows" ]; then + my_distro=$(wmic os get Caption) + my_distro=${my_distro/Caption/} + my_distro=$(trim "${my_distro/Microsoft /}") + my_distro=${my_distro%%+([[:space:]])} + [[ ${my_distro} =~ [[:space:]](.*) ]] && my_distro=${BASH_REMATCH[1]} + elif [[ ${my_os} =~ [Mm]ac ]]; then + case ${osx_version} in + 10.4*) my_distro="Mac OS X Tiger" ;; + 10.5*) my_distro="Mac OS X Leopard" ;; + 10.6*) my_distro="Mac OS X Snow Leopard" ;; + 10.7*) my_distro="Mac OS X Lion" ;; + 10.8*) my_distro="OS X Mountain Lion" ;; + 10.9*) my_distro="OS X Mavericks" ;; + 10.10*) my_distro="OS X Yosemite" ;; + 10.11*) my_distro="OS X El Capitan" ;; + 10.12*) my_distro="macOS Sierra" ;; + 10.13*) my_distro="macOS High Sierra" ;; + 10.14*) my_distro="macOS Mojave" ;; + 10.15*) my_distro="macOS Catalina" ;; + 10.16*) my_distro="macOS Big Sur" ;; + 11.0*) my_distro="macOS Big Sur" ;; + *) my_distro="macOS" ;; + esac + fi + + # shellcheck disable=SC1090,SC2034 + { + case ${my_distro,,} in + aldos) my_distro="ALDOS" ;; + alpine) my_distro="Alpine Linux" ;; + amzn | amazon | amazon*linux) my_distro="Amazon Linux" ;; + arch | arch*linux) my_distro="Arch Linux" ;; + arch32) + my_distro="Arch Linux 32" + [ -z "${ascii_distro}" ] && ascii_distro="Arch Linux" + ;; + arcolinux | arcolinux*) my_distro="ArcoLinux" ;; + artix | artix*linux) my_distro="Artix Linux" ;; + blackpantheros | black*panther*) my_distro="blackPanther OS" ;; + bunsenlabs) my_distro="BunsenLabs" ;; + centos) my_distro="CentOS" ;; + centos*stream) + my_distro="CentOS Stream" + [ -z "${ascii_distro}" ] && ascii_distro="CentOS" + ;; + chakra) my_distro="Chakra" ;; + chrome* | chromium*) my_distro="Chrome OS" ;; + crux) my_distro="CRUX" ;; + debian) + my_distro="Debian" + . "${FETCH_DATA_DIR}/lib/distro/debian/lib.sh" + ;; + devuan) my_distro="Devuan" ;; + deepin) my_distro="Deepin" ;; + dragonflybsd) my_distro="DragonFlyBSD" ;; + dragora) my_distro="Dragora" ;; + drauger*) my_distro="DraugerOS" ;; + elementary | 'elementary os') my_distro="elementary OS" ;; + endeavour*) my_distro="EndeavourOS" ;; + eurolinux) my_distro="EuroLinux" ;; + evolveos) my_distro="Evolve OS" ;; + exherbo | exherbo*linux) my_distro="Exherbo" ;; + fedora) + my_distro="Fedora" + . "${FETCH_DATA_DIR}/lib/distro/fedora/lib.sh" + ;; + freebsd) my_distro="FreeBSD" ;; + frugalware) my_distro="Frugalware" ;; + funtoo) my_distro="Funtoo" ;; + gentoo) + my_distro="Gentoo" + . "${FETCH_DATA_DIR}/lib/distro/gentoo/lib.sh" + ;; + gnewsense) my_distro="gNewSense" ;; + guix*system) my_distro="Guix System" ;; + haiku) my_distro="Haiku" ;; + hyperbolagnu | hyperbolagnu/linux-libre | 'hyperbola gnu/linux-libre' | hyperbola) + my_distro="Hyperbola GNU/Linux-libre" + [ -z "${ascii_distro}" ] && ascii_distro="Hyperbola" + ;; + kali*linux) my_distro="Kali Linux" ;; + kaos) my_distro="KaOS" ;; + kde*neon | neon) + my_distro="KDE neon" + . "${FETCH_DATA_DIR}/lib/distro/kde-neon/lib.sh" + ;; + kogaion) my_distro="Kogaion" ;; + lmde) my_distro="LMDE" ;; + lunar | lunar*linux) my_distro="Lunar Linux" ;; + *"macos"* | *"mac os x"*) + [ -z "${ascii_distro}" ] && ascii_distro="macOS" + ;; + manjaro) my_distro="Manjaro" ;; + mageia) my_distro="Mageia" ;; + mer) my_distro="Mer" ;; + mint | linux*mint) + my_distro="Mint" + . "${FETCH_DATA_DIR}/lib/distro/mint/lib.sh" + ;; + netbsd) my_distro="NetBSD" ;; + netrunner) my_distro="Netrunner" ;; + nix | nix*os) my_distro="NixOS" ;; + obarun) my_distro="Obarun" ;; + ol | oracle*linux) my_distro="Oracle Linux" ;; + openbsd) my_distro="OpenBSD" ;; + os*elbrus) my_distro="OS Elbrus" ;; + parabolagnu | parabolagnu/linux-libre | 'parabola gnu/linux-libre' | parabola) + my_distro="Parabola GNU/Linux-libre" + [ -z "${ascii_distro}" ] && ascii_distro="Parabola" + ;; + parrot | parrot*security) my_distro="Parrot Security" ;; + pclinuxos | pclos) my_distro="PCLinuxOS" ;; + peppermint) my_distro="Peppermint" ;; + proxmox | proxmox*ve) my_distro="Proxmox VE" ;; + pureos) my_distro="PureOS" ;; + qubes) my_distro="Qubes OS" ;; + raspbian) my_distro="Raspbian" ;; + red*hat* | rhel) + my_distro="Red Hat Enterprise Linux" + [ -z "${ascii_distro}" ] && ascii_distro="RHEL" + ;; + rosa) my_distro="ROSA" ;; + sabayon) my_distro="Sabayon" ;; + sailfish | sailfish*os) + my_distro="SailfishOS" + . "${FETCH_DATA_DIR}/lib/distro/sailfish/lib.sh" + ;; + scientific*) my_distro="Scientific Linux" ;; + siduction) my_distro="Siduction" ;; + smgl | source*mage | source*mage*gnu*linux) + my_distro="Source Mage GNU/Linux" + [ -z "${ascii_distro}" ] && ascii_distro="SourceMage" + ;; + solus) my_distro="Solus" ;; + sparky | sparky*linux) my_distro="SparkyLinux" ;; + steam | steam*os) my_distro="SteamOS" ;; + sulin) my_distro="Sulin" ;; + *suse*) + my_distro="openSUSE" + . "${FETCH_DATA_DIR}/lib/distro/suse/lib.sh" + [ -z "${ascii_distro}" ] && ascii_distro="SUSE" + ;; + tinycore | tinycore*linux) my_distro="TinyCore" ;; + trisquel) my_distro="Trisquel" ;; + ubuntu) + my_distro="Ubuntu" + . "${FETCH_DATA_DIR}/lib/distro/ubuntu/lib.sh" + ;; + void*linux) my_distro="Void Linux" ;; + *"windows"*) + [ -z "${ascii_distro}" ] && ascii_distro="Windows" + ;; + zorin*) my_distro="Zorin OS" ;; + *) + ascii_distro="Unknown" + config_ascii['colors']="random" + ;; + esac + } + + [ -z "${ascii_distro}" ] && ascii_distro="${my_distro}" + + [ -n "${ascii_distro}" ] && ascii_distro="${ascii_distro// /-}" + + if [ -f "${FETCH_DATA_DIR}/ascii/${ascii_distro,,}.sh" ]; then + # shellcheck source=/dev/null + . "${FETCH_DATA_DIR}/ascii/${ascii_distro,,}.sh" + else + # shellcheck disable=SC1094,SC1090 + . "${FETCH_DATA_DIR}/ascii/unknown.sh" + fi + + # shellcheck disable=SC2154 + case ${config_distro[short]} in + on) + : + ;; + version) + [ -n "${distro_release}" ] && my_distro+=" ${distro_release}" + ;; + codename) + [ -n "${distro_codename}" ] && my_distro+=" ${distro_codename}" + ;; + + full) + [ -n "${distro_release}" ] && my_distro+=" ${distro_release}" + [ -n "${distro_codename}" ] && my_distro+=" ${distro_codename}" + ;; + auto | *) + # shellcheck disable=SC2154 + if [[ ${config_global[short]} =~ 'on' ]]; then + : + else + [ -n "${distro_release}" ] && my_distro+=" ${distro_release}" + [ -n "${distro_codename}" ] && my_distro+=" ${distro_codename}" + fi + ;; + esac + + # TODO: turn into case + [[ ${config_distro[os_arch]} =~ 'on' ]] && my_distro+=" ${kernel_machine}" + + # Return my_distro value for print_info() + #printf '%b' "$(trim "${my_distro}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding distribution...found as '${my_distro}'." +} diff --git a/lib/detection/kernel.sh b/lib/detection/kernel.sh new file mode 100644 index 0000000..b8f91f6 --- /dev/null +++ b/lib/detection/kernel.sh @@ -0,0 +1,28 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154,SC2034 +detect_kernel() { + # shellcheck disable=SC2154 + case ${config_kernel[short]} in + on) + my_kernel="${kernel_version}" + ;; + off) + my_kernel="${kernel_name} ${kernel_version}" + ;; + auto) + # shellcheck disable=SC2154 + if [[ ${config_global[short]} =~ 'on' ]]; then + my_kernel="${kernel_version}" + else + my_kernel="${kernel_name} ${kernel_version}" + fi + ;; + *) return ;; + esac + + # Return my_kernel value for print_info() + #printf '%b' "$(trim "${my_kernel}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding kernel...found as '${my_kernel}'." +} diff --git a/lib/detection/memory.sh b/lib/detection/memory.sh new file mode 100644 index 0000000..c625d4f --- /dev/null +++ b/lib/detection/memory.sh @@ -0,0 +1,86 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_memory() { + case ${my_os} in + "Linux" | "Windows") + # MemUsed = Memtotal + Shmem - MemFree - Buffers - Cached - SReclaimable + # Source: https://github.com/KittyKatt/screenFetch/issues/386#issuecomment-249312716 + while IFS=":" read -r a b; do + case ${a} in + "MemTotal") + ((mem_used += ${b/kB/})) + mem_total="${b/kB/}" + ;; + "Shmem") ((mem_used += ${b/kB/})) ;; + "MemFree" | "Buffers" | "Cached" | "SReclaimable") + mem_used="$((mem_used -= ${b/kB/}))" + ;; + "MemAvailable") + mem_avail=${b/kB/} + ;; + esac + done < /proc/meminfo + + if [ -n "${mem_avail}" ]; then + mem_used=$(((mem_total - mem_avail) / 1024)) + else + mem_used="$((mem_used / 1024))" + fi + + mem_total="$((mem_total / 1024))" + ;; + "BSD") + case ${kernel_name} in + "NetBSD"*) mem_total="$(($(sysctl -n hw.physmem64) / 1024 / 1024))" ;; + *) mem_total="$(($(sysctl -n hw.physmem) / 1024 / 1024))" ;; + esac + + case ${kernel_name} in + "NetBSD"*) + mem_free="$(($(awk -F ':|kB' '/MemFree:/ {printf $2}' /proc/meminfo) / 1024))" + ;; + "FreeBSD"* | "DragonFly"*) + hw_pagesize="$(sysctl -n hw.pagesize)" + mem_inactive="$(($(sysctl -n vm.stats.vm.v_inactive_count) * hw_pagesize))" + mem_unused="$(($(sysctl -n vm.stats.vm.v_free_count) * hw_pagesize))" + mem_cache="$(($(sysctl -n vm.stats.vm.v_cache_count) * hw_pagesize))" + mem_free="$(((mem_inactive + mem_unused + mem_cache) / 1024 / 1024))" + ;; + "OpenBSD"*) ;; + *) mem_free="$(($(vmstat | awk 'END {printf $5}') / 1024))" ;; + esac + + case ${kernel_name} in + "OpenBSD"*) + mem_used="$(vmstat | awk 'END {printf $3}')" + mem_used="${mem_used/M/}" + ;; + *) mem_used="$((mem_total - mem_free))" ;; + esac + ;; + "Mac OS X" | "macOS") + mem_total="$(($(sysctl -n hw.memsize) / 1024 / 1024))" + mem_wired="$(vm_stat | awk '/ wired/ { print $4 }')" + mem_active="$(vm_stat | awk '/ active/ { printf $3 }')" + mem_compressed="$(vm_stat | awk '/ occupied/ { printf $5 }')" + mem_compressed="${mem_compressed:-0}" + mem_used="$(((${mem_wired//./} + ${mem_active//./} + ${mem_compressed//./}) * 4 / 1024))" + ;; + "Haiku") + mem_total="$(($(sysinfo -mem | awk -F '\\/ |)' '{print $2; exit}') / 1024 / 1024))" + mem_used="$(sysinfo -mem | awk -F '\\/|)' '{print $2; exit}')" + mem_used="$((${mem_used/max/} / 1024 / 1024))" + ;; + esac + + # shellcheck disable=SC2154 + [ "${config_memory[percent]}" == "on" ] && ((mem_perc = mem_used * 100 / mem_total)) + + my_memory="${mem_used}${mem_label:-MiB} / ${mem_total}${mem_label:-MiB} ${mem_perc:+(${mem_perc}%)}" + + # Return my_memory value for print_info() + #printf '%b' "$(trim "${my_memory}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding memory usage...found as '${my_memory}'." +} diff --git a/lib/detection/os.sh b/lib/detection/os.sh new file mode 100644 index 0000000..4b4ae36 --- /dev/null +++ b/lib/detection/os.sh @@ -0,0 +1,28 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_os() { + case "${kernel_name}" in + Darwin) my_os=${darwin_name} ;; + SunOS) my_os=Solaris ;; + Haiku) my_os=Haiku ;; + MINIX) my_os=MINIX ;; + AIX) my_os=AIX ;; + IRIX*) my_os=IRIX ;; + FreeMiNT) my_os=FreeMiNT ;; + Linux | GNU*) + my_os=Linux + ;; + *BSD | DragonFly | Bitrig) + my_os=BSD + ;; + CYGWIN* | MSYS* | MINGW*) + my_os=Windows + ;; + *) + errorOut "Unknown OS detected, please report this issue." + ;; + esac + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding OS...found as '${my_os}'." +} diff --git a/lib/detection/packages.sh b/lib/detection/packages.sh new file mode 100644 index 0000000..d910ddb --- /dev/null +++ b/lib/detection/packages.sh @@ -0,0 +1,188 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_packages() { + # most of this is pulled from neofetch with small edits to line up with + # previous screenfetch functionality + + # to adjust the number of pkgs per pkg manager + pkgs_h=0 + + # _has: Check if package manager installed. + # _dir: Count files or dirs in a glob. + # _pac: If packages > 0, log package manager name. + # _tot: Count lines in command output. + _has() { type -p "${1}" > /dev/null && manager=${1}; } + _dir() { + ((my_packages += $#)) + _pac "$(($# - pkgs_h))" + } + _pac() { + ((${1} > 0)) && { + managers+=("${1} (${manager})") + manager_string+="${manager}, " + } + } + _tot() { + IFS=$'\n' read -d "" -ra pkgs <<< "$("$@" 2> /dev/null)" + ((my_packages += ${#pkgs[@]})) + _pac "$((${#pkgs[@]} - pkgs_h))" + } + + # Redefine _tot() for Bedrock Linux. + [[ -f /bedrock/etc/bedrock-release && ${PATH} == */bedrock/cross/* ]] && { + _tot() { + IFS=$'\n' read -d "" -ra pkgs <<< "$(for s in $(brl list); do strat -r "${s}" "${@}"; done)" + ((my_packages += "${#pkgs[@]}")) + _pac "$((${#pkgs[@]} - pkgs_h))" + } + br_prefix="/bedrock/strata/*" + } + + # get total packages based on OS value + case ${my_os} in + Linux | BSD | Solaris) + # simple commands + _has kiss && _tot kiss 1 + _has cpt-list && _tot cpt-list + _has pacman-key && _tot pacman -Qq --color never + _has apt && _tot dpkg-query -W # dpkg-query is much faster than apt + _has rpm && _tot rpm -qa + _has xbps-query && _tot xbps-query -list + _has apk && _tot apk info + _has opkg && _tot opkg list-installed + _has pacman-g2 && _tot pacman-g2 -q + _has lvu && _tot lvu installed + _has tce-status && _tot tce-status -lvu + _has pkg_info && _tot pkg_info + _has tazpkg && pkgs_h=6 _tot tazpkg list && ((my_packages -= 6)) + _has sorcery && _tot gaze installed + _has alps && _tot alps showinstalled + _has butch && _tot butch list + _has swupd && _tot swupd bundle-list --quiet + _has pisi && _tot pisi list-installed + _has inary && _tot inary li + + # 'mine' conflicts with minesweeper games. + [[ -f /etc/SDE-VERSION ]] && _has mine && _tot mine -q + + # file/dir count + # $br_prefix is apparently fixed and won't change based on user input + # shellcheck disable=SC2086 + { + shopt -s nullglob + _has brew && _dir "$(brew --cellar)"/* + _has emerge && _dir ${br_prefix}/var/db/pkg/*/*/ + _has Compile && _dir ${br_prefix}/Programs/*/ + _has eopkg && _dir ${br_prefix}/var/lib/eopkg/package/* + _has crew && _dir ${br_prefix}/usr/local/etc/crew/meta/*.filelist + _has pkgtool && _dir ${br_prefix}/var/log/packages/* + _has scratch && _dir ${br_prefix}/var/lib/scratchpkg/index/*/.pkginfo + _has kagami && _dir ${br_prefix}/var/lib/kagami/pkgs/* + _has cave && _dir ${br_prefix}/var/db/paludis/repositories/cross-installed/*/data/*/ \ + ${br_prefix}/var/db/paludis/repositories/installed/data/*/ + shopt -u nullglob + } + + # Complex commands + _has kpm-pkg && ((my_packages += $(kpm --get-selections | grep -cv deinstall$))) + _has guix && { + manager=guix-system && _tot guix package -p "/run/current-system/profile" -I + manager=guix-user && _tot guix package -I + } + _has nix-store && { + nix-user-pkgs() { + nix-store -qR ~/.nix-profile + nix-store -qR /etc/profiles/per-user/"${USER}" + } + manager=nix-system && _tot nix-store -qR /run/current-system/sw + manager=nix-user && _tot nix-user-pkgs + manager=nix-default && _tot nix-store -qR /nix/var/nix/profiles/default + } + + # pkginfo is also the name of a python package manager which is painfully slow. + # TODO: Fix this somehow. (neofetch) + _has pkginfo && _tot pkginfo -i + + # BSD-like package detection + case ${kernel_name} in + FreeBSD | DragonFly) _has pkg && _tot pkg info ;; + *) + _has pkg && _dir /var/db/pkg/* + ((my_packages == 0)) && _has pkg && _tot pkg list + ;; + esac + + # list these last as they accompany regular package managers. + _has flatpak && _tot flatpak list + _has spm && _tot spm list -i + _has puyo && _dir ~/.puyo/installed + + # Snap hangs if the command is run without the daemon running. + # Only run snap if the daemon is also running. + _has snap && pgrep -x snapd > /dev/null && + pkgs_h=1 _tot snap list && ((my_packages -= 1)) + + # This is the only standard location for appimages. + # See: https://github.com/AppImage/AppImageKit/wiki + manager=appimage && _has appimaged && _dir ~/.local/bin/*.appimage + ;; + "Mac OS X" | "macOS") + _has port && pkgs_h=1 _tot port installed && ((my_packages -= 1)) + _has brew && _dir /usr/local/Cellar/* + _has nix-store && { + nix-user-pkgs() { + nix-store -qR ~/.nix-profile + nix-store -qR /etc/profiles/per-user/"${USER}" + } + manager=nix-system && _tot nix-store -qR /run/current-system/sw + manager=nix-user && _tot nix-store -qR nix-user-pkgs + } + ;; + Windows) + case ${kernel_name} in + CYGWIN*) _has cygcheck && _tot cygcheck -cd ;; + MSYS*) _has pacman && _tot pacman -Qq --color never ;; + *) : ;; + esac + + # Scoop environment throws errors if `tot scoop list` is used + _has scoop && pkgs_h=1 _dir ~/scoop/apps/* && ((my_packages -= 1)) + + # Count chocolatey packages. + _has choco && _dir /c/ProgramData/chocolatey/lib/* + [ -d /cygdrive/c/ProgramData/chocolatey/lib ] && + manager=choco _dir /cygdrive/c/ProgramData/chocolatey/lib/* + ;; + Haiku) + _has pkgman && _dir /boot/system/package-links/* + my_packages=${my_packages/pkgman/depot} + ;; + *) return ;; + esac + + if ((my_packages == 0)); then + unset my_packages + else + # shellcheck disable=SC2154 + case ${config_packages[managers]} in + off) + : + ;; + split) + printf -v my_packages '%s, ' "${managers[@]}" + my_packages=${my_packages%,*} + ;; + on | *) + my_packages+=" (${manager_string%,*})" + ;; + esac + # replace pacman-key with pacman + my_packages=${my_packages/pacman-key/pacman} + fi + + # Return my_packages value for print_info() + #printf '%b' "$(trim "${my_packages}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding current package count...found as '${my_packages}'." +} diff --git a/lib/detection/shell.sh b/lib/detection/shell.sh new file mode 100644 index 0000000..c5aca51 --- /dev/null +++ b/lib/detection/shell.sh @@ -0,0 +1,76 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_shell() { + # get configuration on whether full shell path should be displayed + # shellcheck disable=SC2154 + case ${config_shell[path]} in + on) shell_type="${SHELL}" ;; + off | *) shell_type="${SHELL##*/}" ;; + esac + + # if version_info is off, then return what we have now + # shellcheck disable=SC2154 + [ "${config_shell[version]}" != "on" ] && my_shell="${shell_type}" && return + + # Possible Windows problem + [ "${my_os}" == "Windows" ] && shell_name="${shell_type//\.exe/}" + + # get shell versions + my_shell="${shell_name:=${shell_type}} " + + case ${shell_name:=${SHELL##*/}} in + bash) + # shellcheck disable=SC2016 + [ -n "${BASH_VERSION}" ] || BASH_VERSION=$("${SHELL}" -c 'printf %s "$BASH_VERSION"') + my_shell+="${BASH_VERSION/-*/}" + ;; + sh | ash | dash | es) ;; + *ksh) + # shellcheck disable=SC2154,SC2016 + my_shell+=$("${SHELL}" -c 'printf %s "$KSH_VERSION"') + my_shell=${my_shell/ * KSH/} + my_shell=${my_shell/version/} + ;; + osh) + # shellcheck disable=SC2016 + { + if [[ -n ${OIL_VERSION} ]]; then + my_shell+=${OIL_VERSION} + else + my_shell+=$("${SHELL}" -c 'printf %s "$OIL_VERSION"') + fi + } + ;; + tcsh) + # shellcheck disable=SC2016 + my_shell+=$("${SHELL}" -c 'printf %s "$tcsh"') + ;; + yash) + my_shell+=$("${SHELL}" --version 2>&1) + my_shell=${my_shell/ ${shell_name}/} + my_shell=${my_shell/ Yet another shell/} + my_shell=${my_shell/Copyright*/} + ;; + fish) + # shellcheck disable=SC2016 + [ -n "${FISH_VERSION}" ] || FISH_VERSION=$("${SHELL}" -c 'printf %s "$FISH_VERSION"') + my_shell+="${FISH_VERSION}" + ;; + *) + my_shell+=$("${SHELL}" --version 2>&1) + my_shell=${my_shell/ ${shell_name}/} + ;; + esac + + # remove unwanted + my_shell=${my_shell/, version/} + my_shell=${my_shell/xonsh\//xonsh } + my_shell=${my_shell/options*/} + my_shell=${my_shell/\(*\)/} + + # Return my_shell value for print_info() + #printf '%b' "$(trim "${my_shell}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding current shell...found as '${my_shell}'." +} diff --git a/lib/detection/uptime.sh b/lib/detection/uptime.sh new file mode 100644 index 0000000..0a922db --- /dev/null +++ b/lib/detection/uptime.sh @@ -0,0 +1,84 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_uptime() { + # get seconds up since boot + case ${my_os} in + "Mac OS X" | "macOS" | BSD) + boot=$(sysctl -n kern.boottime) + [[ ${boot} =~ [0-9]+ ]] && boot=${BASH_REMATCH[0]} + now=$(date +%s) + _seconds=$((now - boot)) + ;; + Linux | Windows | [G | g][N | n][U | u]) + if [ -f /proc/uptime ]; then + _seconds=$(< /proc/uptime) + _seconds=${_seconds//.*/} + else + boot=$(date -d"$(uptime -s)" +%s) + now=$(date +%s) + _seconds=$((now - boot)) + fi + ;; + Haiku) + _seconds=$(($(system_time) / 1000000)) + ;; + *) return ;; + esac + + # math! + _mins="$((_seconds / 60 % 60)) minutes" + _hours="$((_seconds / 3600 % 24)) hours" + _days="$((_seconds / 86400)) days" + + # get rid of plurals + ((${_mins/ */} == 1)) && _mins=${_mins/s/} + ((${_hours/ */} == 1)) && _hours=${_hours/s/} + ((${_days/ */} == 1)) && _days=${_days/s/} + + # don't output if field is empty + ((${_mins/ */} == 0)) && unset _mins + ((${_hours/ */} == 0)) && unset _hours + ((${_days/ */} == 0)) && unset _days + + # build the uptime line + my_uptime=${_days:+${_days}, }${_hours:+${_hours}, }${_mins} + my_uptime=${my_uptime%', '} + my_uptime=${my_uptime:-${_seconds} seconds} + + # shorthand + # shellcheck disable=SC2154 + case ${config_uptime[short]} in + on) + my_uptime=${my_uptime/ minutes/ mins} + my_uptime=${my_uptime/ minute/ min} + my_uptime=${my_uptime/ seconds/ secs} + ;; + tiny) + my_uptime=${my_uptime/ days/d} + my_uptime=${my_uptime/ day/d} + my_uptime=${my_uptime/ hours/h} + my_uptime=${my_uptime/ hour/h} + my_uptime=${my_uptime/ minutes/m} + my_uptime=${my_uptime/ minute/m} + my_uptime=${my_uptime/ seconds/s} + my_uptime=${my_uptime//,/} + ;; + off) + : + ;; + auto | *) + # shellcheck disable=SC2154 + if [ "${config_global[short]}" == 'on' ]; then + my_uptime=${my_uptime/ minutes/ mins} + my_uptime=${my_uptime/ minute/ min} + my_uptime=${my_uptime/ seconds/ secs} + fi + ;; + esac + + # Return my_uptime value for print_info() + #printf '%b' "$(trim "${my_uptime}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding current uptime...found as '${my_uptime}'." +} diff --git a/lib/detection/userinfo.sh b/lib/detection/userinfo.sh new file mode 100644 index 0000000..94f695d --- /dev/null +++ b/lib/detection/userinfo.sh @@ -0,0 +1,31 @@ +# shellcheck shell=bash +# shellcheck disable=SC2154 +detect_userinfo() { + # shellcheck disable=SC2154 + if [ "${config_userinfo[display_user]}" == "on" ]; then + my_user=${USER} + if [ -z "${USER}" ]; then + my_user=$(whoami) + fi + my_userinfo="${my_user}" + fi + + # shellcheck disable=SC2154 + if [ "${config_userinfo[display_hostname]}" == "on" ]; then + my_host="${HOSTNAME}" + if [ "${my_distro}" == "Mac OS X" ] || [ "${my_distro}" == "macOS" ]; then + my_host=${my_host/.local/} + fi + if [ -n "${my_userinfo}" ]; then + my_userinfo="${my_userinfo}@${my_host}" + else + my_userinfo="${my_host}" + fi + fi + + # Return my_userinfo value for print_info() + #printf '%b' "$(trim "${my_userinfo}")" + + # TODO: check verbosity here instead of in function, save function call + verboseOut "Finding user info...found as '${my_userinfo}'." +} diff --git a/sample.config.conf b/sample.config.conf index 0a6f96a..df61d6e 100644 --- a/sample.config.conf +++ b/sample.config.conf @@ -5,19 +5,30 @@ verbose="off" # system directory where fetch distribution and extra files live # default: /usr/share/fetch -data_dir="/usr/share/fetch/lib" +data_dir="/usr/share/fetch" # globally set shorthand on all fields # options: off, on # default: off short="off" -# defined info +# controls info display +# space delimited list of detections to run and display +# detections: userinfo, distro, kernel, uptime, shell, packages +# cpu, memory +# default: userinfo distro kernel uptime shell packages cpu memory info="userinfo distro kernel uptime shell packages cpu memory" [text] +# control whether text information is displayed +# options: on, off +# default: on display="on" bold="on" underline_enabled="on" underline_character="-" +# controls if output is colored +# options: on, off +# default: on +color="on" # character that displays between info title and info data # default: : # example: "DE : GNOME" @@ -25,6 +36,9 @@ info_separator=":" # ASCII Logo Display Options [ascii] +# control whether ASCII logo is displayed +# options: on, off +# default: on display="on" # select which distro logo to display # options: auto, distroname @@ -33,7 +47,7 @@ display="on" # (for full list of distribution names, please refer to man fetch) ascii_distro="auto" # select colorization of ascii logo -# options: distro, 'c1 c2 c3 c4 c5 c6' +# options: distro, random, 'c1 c2 c3 c4 c5 c6' # default: distro # ( fill this variable with up to 6 color names or 256 color number # definitions. note that only the number of color definitions up to the @@ -87,6 +101,9 @@ short="auto" # options: on, off # default: on os_arch="on" +# subtitle for distro line +# default: OS +# to turn off subtitle display, set this variable to empty subtitle="OS" # Kernel Information Display Options @@ -102,6 +119,9 @@ display="on" # on : 5.8.0-1023-gcp # off : Linux 5.8.0-1023-gcp short="auto" +# subtitle for kernel line +# default: Kernel +# to turn off subtitle display, set this variable to empty subtitle="Kernel" # Uptime Information Display Options @@ -118,6 +138,9 @@ display="on" # off : 2 days, 10 hours, 3 minutes # tiny : 2d 10h 3m short="auto" +# subtitle for uptime line +# default: Uptime +# to turn off subtitle display, set this variable to empty subtitle="Uptime" # Installed Packages Information Display Options @@ -134,6 +157,9 @@ display="on" # on : 384 (apt, snap, flatpak) # split : 373 (apt), 7 (snap), 3 (flatpak) managers="split" +# subtitle for packages line +# default: Packages +# to turn off subtitle display, set this variable to empty subtitle="Packages" # Current Shell Information Display Options @@ -153,6 +179,9 @@ version="on" # options: on, off # default: off path="off" +# subtitle for shell line +# default: Shell +# to turn off subtitle display, set this variable to empty subtitle="Shell" # CPU Information Display Options @@ -190,6 +219,9 @@ cores="on" # F : Intel Xeon E5-2650 v2 (16) @ 2.6GHz [82.0°F] # off : Intel Xeon E5-2650 v2 (16) @ 2.6GHz temp="off" +# subtitle for cpu line +# default: CPU +# to turn off subtitle display, set this variable to empty subtitle="CPU" # Memory Information Display Options @@ -205,6 +237,9 @@ display="on" # on : 5439MiB / 7653MiB (71%) # off : 5439MiB / 7653MiB percent="on" +# subtitle for memory line +# default: Memory +# to turn off subtitle display, set this variable to empty subtitle="Memory" # GPU Information Display Options