#!/usr/bin/env bash # SPDX-FileCopyrightText: 2022 Patrick Spek # # SPDX-License-Identifier: AGPL-3.0-or-later # shellcheck source=lib/util/config.bash . "$BASHTARD_LIBDIR/util/config.bash" # shellcheck source=lib/util/pkg.bash . "$BASHTARD_LIBDIR/util/pkg.bash" # shellcheck source=lib/util/svc.bash . "$BASHTARD_LIBDIR/util/svc.bash" # Change the working directory. In usage, this is the same as using cd, # however, it will make additional checks to ensure everything is going fine. chgdir() { debug "bashtard/chgdir" "Changing workdir to $1" cd -- "$1" || die "Failed to change directory to $1" } # Create a datetime stamp. This is a wrapper around the date utility, ensuring # that the date being formatted is always in UTC and respect SOURCE_DATE_EPOCH, # if it is set. datetime() { local date_opts date_opts+=("-u") # Apply SOURCE_DATE_EPOCH as the date to base off of. if [[ $SOURCE_DATE_EPOCH ]] then date_opts+=("-d@$SOURCE_DATE_EPOCH") fi date "${date_opts[@]}" +"${1:-%FT%TZ}" } # Log a message as error, and exit the program. This is intended for serious # issues that prevent the script from running correctly. The exit code can be # specified with -i, or will default to 1. die() { local OPTIND local code while getopts ":i:" opt do case "$opt" in i) code=$OPTARG ;; *) alert "bashtard/die" "Unused argument specified: $opt" ;; esac done shift $(( OPTIND -1 )) alert "$@" exit "${code:-1}" } # Fetch a file from an URL. Using this function introduces a dependency on curl. fetch_http() { local OPTIND local buffer while getopts ":o:" opt do case "$opt" in o) buffer=$OPTARG ;; *) alert "bashtard/fetch_http" "Unused argument specified: $opt" ;; esac done shift $(( OPTIND -1 )) [[ -z $buffer ]] && buffer="$(tmpfile)" notice "bashtard/fetch_http" "Downloading $1 to $buffer" for util in curl wget do command -v "$util" > /dev/null || continue "fetch_http_$util" "$1" "$buffer" || continue local exit_code=$? printf "%s" "$buffer" return $exit_code done die "bashtard/fetch_http" "Unable to download file over HTTP!" } fetch_http_curl() { curl -Ls "$1" > "$2" } fetch_http_wget() { wget --quiet --output-document "$2" "$1" } # Check if the first argument given appears in the list of all following # arguments. in_args() { local needle="$1" shift for arg in "$@" do [[ $needle == "$arg" ]] && return 0 done return 1 } # Join a list of arguments into a single string. By default, this will join # using a ",", but you can set a different character using -c. Note that this # only joins with a single character, not a string of characters. join_args() { local OPTIND local IFS="," while getopts ":c:" opt do case "$opt" in c) IFS="$OPTARG" ;; *) warn "bashtard/join_args" "Unused opt specified: $opt" ;; esac done shift $(( OPTIND - 1)) printf "%s" "$*" } # Recursively hash files in a directory, and hashing the output of all those # hashes again. This results in a single hash representing the state of files # in a directory. It can be used to check whether contents changed after # templating files in a given directory. file_rhash() { find "$1" -type f -exec sha1sum {} \; \ | sha1sum \ | awk '{ print $1 }' } file_template() { local file="$BASHTARD_ETCDIR/playbooks.d/$BASHTARD_PLAYBOOK/share/$1" ; shift local sedfile sedfile="$(tmpfile)" if [[ ! -f $file ]] then crit "bashtard/template" "Tried to render template from $file, but it doesn't exist" return fi for kv in "$@" do debug "bashtard/template" "Adding $kv to sedfile at $sedfile" key="$(awk -F= '{ print $1 }' <<< "$kv")" if [[ -z "$key" ]] then crit "bashtard/template" "Empty key in '$kv' while rendering $file?" fi value="$(awk -F= '{ print $NF }' <<< "$kv")" if [[ -z "$value" ]] then crit "bashtard/template" "Empty key in '$kv' while rendering $file?" fi # shellcheck disable=SC2016 printf 's@${%s}@%s@g\n' "$key" "$value" >> "$sedfile" done sed -f "$sedfile" "$file" } # Create a temporary directory. Similar to tempfile, but you'll get a directory # instead. tmpdir() { local dir dir="$(mktemp -d)" # Ensure the file was created succesfully if [[ ! -d "$dir" ]] then die "bashtard/tmpdir" "Failed to create a temporary directory at $dir" fi debug "bashtard/tmpdir" "Temporary file created at $dir" printf "%s" "$dir" } # Create a temporary file. In usage, this is no different from mktemp itself, # however, it will apply additional checks to ensure everything is going # correctly, and the files will be cleaned up automatically at the end. tmpfile() { local file file="$(mktemp)" # Ensure the file was created succesfully if [[ ! -f "$file" ]] then die "bashtard/tmpfile" "Failed to create a temporary file at $file" fi debug "bashtard/tmpfile" "Temporary file created at $file" printf "%s" "$file" }