Skip to content

Instantly share code, notes, and snippets.

@Guiorgy
Last active June 20, 2025 15:05
Show Gist options
  • Save Guiorgy/c3a38ddb9b6f0e6284891388065b971f to your computer and use it in GitHub Desktop.
Save Guiorgy/c3a38ddb9b6f0e6284891388065b971f to your computer and use it in GitHub Desktop.
Download the latest, or a specified, Fastfetch release source and build a DEB package
#!/usr/bin/env bash
# Copyright © 2024 Guiorgy
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.
#
# You can see the full GNU General Public License at
# <https://www.gnu.org/licenses/> for more details.
# usage examples:
# $ ./build.sh
# $ ./build.sh 2.7.0
set -Eeo pipefail # exit on error
handle_error() {
error_code=$?
echo -e "${RED}Script failed on line #${1} with error code ${error_code}!${NOCOLOR}" 1>&2
cleanup
exit $error_code
}
trap 'handle_error $LINENO' ERR
# colors for colored output
NOCOLOR='\033[0m'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[0;37m'
error() {
echo -e "${RED}Error${NOCOLOR}: ${1}" 1>&2
cleanup
if [[ -n "$2" ]]; then
exit "$2"
else
exit 1
fi
}
information() {
COLOR="$YELLOW"
if [ $# -gt 1 ]; then
case "$1" in
--*)
case "$1" in
--no-color) COLOR="$NOCOLOR" ;;
--red) COLOR="$RED" ;;
--green) COLOR="$GREEN" ;;
--yellow) COLOR="$YELLOW" ;;
--blue) COLOR="$BLUE" ;;
--purple) COLOR="$PURPLE" ;;
--cyan) COLOR="$CYAN" ;;
--white) COLOR="$WHITE" ;;
*) error 'Unrecognized color' ;;
esac
shift
;;
*) ;;
esac
fi
if [[ $# -gt 1 ]]; then
if [[ -n "$1" ]]; then
echo -e -n "${COLOR}${1}${NOCOLOR}: "
fi
shift
else
echo -e -n "${COLOR}Information${NOCOLOR}: "
fi
echo -e "$1"
}
cleanupAttempted=0
cleanup() {
if [[ $cleanupAttempted -eq 1 ]]; then
return
fi
cleanupAttempted=1
# return to the initial working directory
cd "$workingDirectory"
if [[ -f "${releaseTag}.tar.gz" ]]; then
information 'Cleanup' "Removing the downloaded source archive '${BLUE}${releaseTag}.tar.gz${NOCOLOR}'"
rm "${releaseTag}.tar.gz"
fi
if [[ -d "fastfetch-${releaseTag}" ]]; then
information 'Cleanup' "Removing the extracted source directory '${BLUE}fastfetch-${releaseTag}${NOCOLOR}'"
rm -rf "fastfetch-${releaseTag}"
fi
}
# remember the current working directory for cleanup
workingDirectory=$(pwd)
# check if cmake is available
if ! command -v cmake &>/dev/null; then
error "CMake is not installed. Run '${BLUE}sudo apt install cmake${NOCOLOR}' to install"
fi
# check if curl is available
if ! command -v curl &>/dev/null; then
error "Curl is not installed. Run '${BLUE}sudo apt install curl${NOCOLOR}' to install"
fi
# check if a specific release tag was passed as the first argument
releaseTag="$1"
if [[ -z "$releaseTag" ]]; then
information '' 'Getting the latest release tag from github'
response=$(curl --silent --show-error 'https://api.github.com/repos/fastfetch-cli/fastfetch/releases/latest')
releaseTag=$(grep -m 1 '"tag_name"' <<< "$response" | cut -d : -d '"' -f 4) \
|| error "Failed to grep the release tag. Response: ${BLUE}${response}${NOCOLOR}"
information '' "Latest release tag: ${BLUE}${releaseTag}${NOCOLOR}"
fi
# validate that the release tag is in the format "x.y.z"
if ! [[ "$releaseTag" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
error "The specified release tag '${BLUE}${releaseTag}${NOCOLOR}' is not in the correct format"
fi
# get the list of already built tags
builtTags=$(find . -mindepth 1 -maxdepth 1 -type f -name '*.deb')
if [[ -n "$builtTags" ]]; then
builtTags=$( \
echo "$builtTags" \
| grep -o 'fastfetch-[0-9]\+\.[0-9]\+\.[0-9]\+-Linux.deb' \
| cut -d - -f 2 \
)
# check if the specified release tag is already built
if [[ "$builtTags" =~ "$releaseTag" ]]; then
information --yellow "Already Built" "Release tag '${BLUE}${releaseTag}${NOCOLOR}' already built"
exit 0
fi
fi
# download source archive
# - s: don't show progress
# - S: show errors
# - L: follow redirects
# - O: keep same file name
curl -sSLO "https://github.com/fastfetch-cli/fastfetch/archive/refs/tags/${releaseTag}.tar.gz" || error "Failed to download release '${BLUE}${releaseTag}${NOCOLOR}'"
# extract the tar.gz archive
# - x: extract
# - v: verbose output
# - z: use gzip
# - f: archive file path
tar -xvzf "${releaseTag}.tar.gz" || error 'Failed to unpack the source archive'
# cd into the extracted directory
cd "fastfetch-${releaseTag}"
# # modify the package target of CMakeLists.txt to only build a DEB package
# sed -i \
# -e 's/set(CPACK_GENERATOR ".*")/set(CPACK_GENERATOR "DEB")/g' \
# CMakeLists.txt \
# || error 'Failed to modify CMakeList.txt'
# create a build directory and cd into it
mkdir -p build
cd build
# build the package
cmake .. \
-DENABLE_SYSTEM_YYJSON=OFF \
-DENABLE_ASAN=OFF \
-DENABLE_LTO=ON \
-DBUILD_FLASHFETCH=OFF \
-DBUILD_TESTS=OFF \
-DSET_TWEAK=OFF \
-DIS_MUSL=OFF \
-DINSTALL_LICENSE=ON \
-DENABLE_EMBEDDED_PCIIDS=OFF \
|| error 'Failed to generate a CMake project build system'
# cmake --build . --target package || error 'Failed to build package using CMake'
cpack --verbose -G DEB || error 'Failed to build package using CMake'
# find the built package for the current platform
package=$(find . -maxdepth 1 -type f -name 'fastfetch-*.deb') \
|| error "Failed to find the built package in -e$(ls | sed -e $'s/^/\t/')"
# move the built package to the initial working directory
mv "$package" ../../"fastfetch-${releaseTag}-Linux.deb" \
|| error "Failed to move the built package '$package' from:\n$(ls | sed -e $'s/^/\t/')\nto:\n$(ls | sed -e $'s/^/\t/')"
# remove downloaded source files and build artifacts
cleanup
# print the done message and instructions to install
information --green 'Done' "Successfully built ${BLUE}fastfetch-${releaseTag}-Linux.deb${NOCOLOR}"
information '' "Run '${BLUE}sudo apt install ./fastfetch-${releaseTag}-Linux.deb${NOCOLOR}' to install"
@Guiorgy
Copy link
Author

Guiorgy commented Mar 12, 2024

The script dumps the built packages in the working directory and expects the user to manually install the package.

You may modify the script to automatically run apt install ./fastfetch-[TAG]-Linux.deb, but instead you may prefer to crate a local package repository and add it to the apt sources:

  • Install dpkg-dev if you don't have it
    sudo apt-get install dpkg-dev
  • Add a line to the bottom of the shell script
    dpkg-scanpackages --multiversion . /dev/null | gzip -9c > Packages.gz
  • Create a source list file inside /etc/apt/sources.list.d/
    nano /etc/apt/sources.list.d/fastfetch-local.list
  • Add a reference to the directory where fastfetch packages are built
    deb [trusted=yes] file:/[PATH_TO_THE_DIRECTORY_WITH_THE_BUILD_SCRIPT] ./
  • Optionally, to remove dpkg-scanpackages warnings on missing override file
    • Create an override file in the directory with the build script, for example
      echo 'fastfetch optional utils' > overrides
    • Modify the shell script to use the created overrides file instead of /dev/null
      dpkg-scanpackages --multiversion . overrides | gzip -9c > Packages.gz

After doing the above and updating apt (apt update) you may simply install/upgrade fastfetch as if it were a normal package

  • apt list -a fastfetch
  • apt install fastfetch
  • apt install --only-upgrade fastfetch

@Guiorgy
Copy link
Author

Guiorgy commented Jun 23, 2024

fastfetch has now been added to the Debian repos (only testing and unstable repos for now)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment