#!/usr/bin/env bash # SPDX-FileCopyrightText: 2023 Patrick Spek # # SPDX-License-Identifier: AGPL-3.0-or-later # Read a particular value from a key/value configuration file. Using this # function introduces a dependency on awk. config() { config_for "${BASHTARD_PLATFORM[fqdn]}" "$@" } config_subkeys() { config_subkeys_for "${BASHTARD_PLATFORM[fqdn]}" "$@" } config_for() { local host=$1 ; shift local key=$1 ; shift # Use a variable definition test to define default, in order to ensure # it is _not_ defined if no argument for it was passed, but _is_ # defined even if an empty string was passed. test -v 1 && { local default=$1 ; shift ; } local default local file local files files=( "$BASHTARD_ETCDIR/secrets" "$BASHTARD_ETCDIR/hosts.d/$host" "$BASHTARD_ETCDIR/os.d/${BASHTARD_PLATFORM[key]}" "$BASHTARD_ETCDIR/defaults" ) if [[ -n "$BASHTARD_PLAYBOOK" ]] then debug "bashtard/config_for" "BASHTARD_PLAYBOOK=$BASHTARD_PLAYBOOK, adding etc entries" files+=( "$(playbook_path "base")/etc/os.d/${BASHTARD_PLATFORM[key]}" "$(playbook_path "base")/etc/defaults" ) fi files+=( "$BASHTARD_SHAREDIR/os.d/${BASHTARD_PLATFORM[key]}" "$BASHTARD_SHAREDIR/defaults" ) # Check configuration files for file in "${files[@]}" do debug "bashtard/config_for" "Checking for '$key' in '$file'" [[ ! -f $file ]] && continue # Check if the lookup is a reference variable, defined by using # &= instead of just a single = as seperator. If this exists, # do a new config_for lookup, this time using the value as the # key for the new lookup. value="$(awk -F= '$1 == "'"$key"'&" { print $0 }' "$file" | cut -d'=' -f 2-)" if [[ -n $value ]] then debug "bashtard/config_for" "Found reference for $key to $value in $file" printf "%s" "$(config_for "$host" "$value")" return fi # Use awk to find the right line, then use cut to get the # actual value. Cutting it out with awk _is_ possible, but # comes with whitespace issues or having to deal with values # containing the seperator (=), so using cut is much simpler # and easier to understand. value="$(awk -F= '$1 == "'"$key"'" { print $0 }' "$file" | cut -d'=' -f 2-)" if [[ -n $value ]] then debug "bashtard/config_for" "Found $key=$value in $file" printf "%s" "$value" return fi done # Return default value, if one has been defined if test -v default then printf "%s" "$default" return fi # Error alert "bashtard/config_for" "No configuration value for $key" } config_subkeys_for() { local host=$1 ; shift local key=$1 ; shift local file local files local results files=( "$BASHTARD_ETCDIR/secrets" "$BASHTARD_ETCDIR/hosts.d/$host" "$BASHTARD_ETCDIR/os.d/${BASHTARD_PLATFORM[key]}" "$BASHTARD_ETCDIR/defaults" ) if [[ -n "$BASHTARD_PLAYBOOK" ]] then debug "bashtard/config_for" "BASHTARD_PLAYBOOK=$BASHTARD_PLAYBOOK, adding etc entries" files+=( "$BASHTARD_ETCDIR/playbooks.d/$BASHTARD_PLAYBOOK/etc/os.d/${BASHTARD_PLATFORM[key]}" "$BASHTARD_ETCDIR/playbooks.d/$BASHTARD_PLAYBOOK/etc/defaults" ) fi files+=( "$BASHTARD_SHAREDIR/os.d/${BASHTARD_PLATFORM[key]}" "$BASHTARD_SHAREDIR/defaults" ) # Check configuration files for file in "${files[@]}" do debug "bashtard/config_subkeys" "Checking for subkeys of '$key' in '$file'" [[ ! -f $file ]] && continue while read -r result do local subkey subkey="$(awk -F. '{ print $1 }' <<< "${result#"$key."}")" debug "bashtard/config_subkeys" "Found '$subkey' as subkey of '$key' through '$result'" results+=("$subkey") done < <(grep "^$key\." "$file" | awk -F= '{ print $1 }') done # Return unique results for result in "${results[@]}" do printf "%s\n" "$result" done | sort -u }