#!/bin/bash
#  config - configuration file support library

set -e

lib_load 'core/script'


######
# Library Initialization

# core_config_lib_init() - Other libs use config_init, so use lib_init.
core_config_lib_init() {
	# $config_load_late - Set to `true` by ``config_load()``,
	# signaling that all future configuration files must be loaded
	# immediately (rather than being deferred).  Internal use only.
	# Default: ``false``
	lib_setting_vars config_load_late
	config_load_late=false

	# $config_types[] - List of valid types of configuration files
	# Default: ``sys user pkg``
	lib_setting_arrays -ro config_types
	config_types=( sys user pkg )

	# $sys_configs[] - Lists the system configurations to load.
	# Default: ``${script_name}.conf ${script_name}.local``
	lib_setting_arrays sys_configs
	config_sys_files_append "$script_name.conf" "$script_name.local"

	# $user_configs[] - Lists the user configurations to load.
	# Default: ``${script_name}.conf``
	lib_setting_arrays user_configs
	config_user_files_append "$script_name.conf"

	# $pkg_configs[] - Lists the package configurations to load.
	# Default: `none`
	lib_setting_arrays pkg_configs

	# $config_debug - If set to true `true`, permits errors in the
	# configuration to allow debugging.
	# Default: ``false``
	lib_setting_vars config_debug

	# $config_init_check - Set to `true` to in order to perform
	# early checking of configuration settings, after initialization
	# but prior to loading any configuration files.
	# Default: ``false``
	lib_setting_vars config_init_check

	core_config_config_check
}


######
# Library Configuration

core_config_config_check() {
	config_init_check=${config_init_check:-false}
	config_debug=${config_debug:-false}
}


######
# Configuration Files

# config_filename() - Prints system configuration filename
# (located in ``$confdir``)
config_sys_filename() { echo "$confdir/$script_name/$1"; }

# config_user_filename() - Prints user configuration filename
# (located in ``$user_confdir``)
config_user_filename() { echo "$user_confdir/$script_name/$1"; }

# config_pkg_filename() - Prints package configuration filename
# (located in ``$srcdir``)
config_pkg_filename() { echo "$1"; }

_config_files_add() {
	local name=$1
	local file
	file=$($filefunc "$name" "$ext")
	$addfunc $listvar "$file"
	! $config_load_late || config_read "$file"
}

# config_files_add() - Inserts or appends ($2) configuration files "$@"
# to the named configuration file list ($1).
#
# The remaining functions in this section encapsulate all valid
# permutations of the first two arguments and should be used in
# preference to direct calls to this function.
# $1 - Configuration file type
# $2 - List function: `insert` or `append`
# $@ - Configuration file names
config_files_add() {
	local filefunc="config_${1}_filename"
	local listvar="${1}_configs"
	local addfunc="list_$2"
	shift 2
	for_each _config_files_add "$@"
}

# config_sys_files_insert() - Inserts system configuration files ($@) to start
# of system configuration file list.
config_sys_files_insert() { config_files_add 'sys' 'insert' "$@"; }

# config_sys_files_append() - Appends system configuration files ($@) to end
# of system configuration file list.
config_sys_files_append() { config_files_add 'sys' 'append' "$@"; }

# config_user_files_insert() - Inserts user configuration files ($@) to start
# of user configuration file list.
config_user_files_insert() { config_files_add 'user' 'insert' "$@"; }

# config_user_files_append() - Appends user configuration files ($@) to end
# of user configuration file list.
config_user_files_append() { config_files_add 'user' 'append' "$@"; }

# config_pkg_files_insert() - Inserts package configuration files ($@) to start
# of package configuration file list.
config_pkg_files_insert() { config_files_add 'pkg' 'insert' "$@"; }

# config_pkg_files_append() - Appends package configuration files ($@) to end
# of package configuration file list.
config_pkg_files_append() { config_files_add 'pkg' 'append' "$@"; }


######
# Public Functions

# config_error() - Generates a warning or error, depending on whether
# ``$config_debug`` is true or false respectively.
config_error() {
	local level
	$config_debug && level=warn || level=error
	$level "$@"
}

######
# Configuration Initialization

# config_init() - Initializes all library and tool settings, prior to
# loading any configuration files.
config_init() {
	for_each_lib config_init_lib
	script_cmd_exec config_init
	# TODO: fix config_check callbacks to permit checking here
	if ! $config_init_check || config_check true; then
		info "configuration settings initialized"
	else
		config_dump
		config_error "configuration initialization failed"
	fi
}

# config_init_lib() - Initializes configuration settings for the named
# library ($1).
config_init_lib() { lib_cmd_exec "$1" config_init; }

######
# Configuration Validation

# config_check() - Ensures all configuration settings are valid
config_check() {
	info "checking configuration settings"
	for_each_lib config_check_lib
	script_cmd_exec config_check
}

# config_check_lib() - Ensures configuration settings are valid for the
# name library ($1).
config_check_lib() { lib_cmd_exec "$1" config_check; }


######
# Configuration File Reading

# config_read() - Reads a single configuration file ($1)
# $1 - filename
config_read() {
	local cfg=$1
	if [ ! -f "$cfg" ]; then
		debug "missing: $cfg"
		return
	fi
	debug "reading: $cfg ..."
	if [ -r "$cfg" ]; then
		eval "$(<"$cfg")"
	else
		eval "$(sudo cat "$cfg")"
	fi
}

# config_read_files() - Reads a list of configuration files ($@)
config_read_files() { for_each config_read "$@"; }


######
# Configuration File Loading

# config_load() - Reads all known configuration files by calling
# ``config_load_kind()`` for each type of configuration file.
# Sets ``$config_load_late`` to ensure all future configuration files
# are loaded immediately by ``config_files_add()``.
config_load() {
	for_each config_load_kind "${config_types[@]}"
	config_load_late=true
}

# config_load_kind() - Reads configuration files of the given type ($1).
# See ``$config_types[]`` for available types.
config_load_kind() {
	local kind=$1

	local -a files
	eval "files=( \"\${${kind}_configs[@]}\" )"

	[ "${files[*]}" ] || return 0
	info "Loading $kind config files..."
	config_read_files "${files[@]}"
}


######
# Config CLI

# config_usage() - Prints usage for the ``config`` command namespace.
config_usage() {
	cat <<USAGE
<cmd> [<var>]
Configuration Commands:
	files [(all|sys|user|pkg)]	Prints the list of config files
	names				Prints the list of setting names
	values <name>+			Prints the values of the named settings
	show [all|<lib>+]		Prints library settings
	load <library>+			Loads the named libraries
USAGE
}

# config_files() - Prints the named list ($1) of configuration files.
# $1 - Type of configuration files: ``all``, ``sys``, ``user``, or ``pkg``.
config_files() {
	case "$1" in
	(sys|user|pkg) _config_files "$1" ;;
	(''|all) config_files_all ;;
	*) error_usage "$1: unknown type, must be ${config_types[*]}" ;;
	esac
	echo
}

# config_files_all() - Prints a list of all configuration files.
config_files_all() {
	local -a _files
	for_each _config_files "${config_types[@]}"
}

_config_files() { eval "list_insert _files \"\${${1}_configs[*]}\""; }

# config_names() - Prints list of active configuration settings.
config_names() {
	local -a opts
	local class
	for class in "${package_libs[@]}" $(script_symbol); do
		local sym
		sym=$(lib_symbol $class)
		list_append opts $(settings_list_all "$sym")
	done
	echo "${opts[*]}"
}

# config_values() - Prints list of configuration settings name/value pairs
# for the given list of setting names ($@).
config_values() {
	min_args 1 "$@"
	for_each _config_value "$@"
}

_config_value() {
	local name=$1
	local class
	for class in "${package_libs[@]}" $(script_symbol); do
		local sym
		sym=$(lib_symbol $class)
		if in_list "$name" $(settings_list_all "$sym"); then
			_config_show "$sym" "$name"
		fi
	done
}

# config_show() - Prints active configuration settings for a given
# library ($1) or all active scripts (if none given).
# $1 - Library name (optional).  If `null`, prints all script settings.
config_show() {
	max_args 1 "$@"
	local class=${1:-all}

	local -a libs
	if [ "$class" = all ]; then
		libs=( "${lib_loaded[@]}" "$(script_symbol)" )
	else
		libs=( $class )
	fi

	if [ ${#libs[*]} -gt 1 ]; then
		for_each config_show "${libs[@]}"
		return
	fi

	local sym
	sym=$(lib_symbol "$class")
	! is_tool "$class" || sym="$(script_symbol)"

	local -a settings
	settings=( $(settings_list_all $sym) )
	if [ -z "${settings[*]}" ]; then
		return
	fi

	echo "######"
	echo "# '$class' settings"
	for_each "_config_show $sym" "${settings[@]}"
}

_config_show() {
	local sym=$1
	local var=$2
	if in_list "$var" $(settings_list_vars "$sym"); then
		_config_show_var "$var"
	elif in_list "$var" $(settings_list_arrays "$sym"); then
		_config_show_array "$var"
	elif in_list "$var" $(settings_list_funcs "$sym"); then
		
	config_show_func "$var"
	else
		error "$sym: $var: not a valid variable name"
	fi
}

_config_show_var() {
	local var=$1
	local -n value=$var
	echo "$var=$(arg_quote "$value")"
}
_config_show_array() {
	local name=$1
	local -a list
	eval "list=( \"\${${name}[@]}\" )"
	list_quote list
	echo "$name=( ${list[*]} )"
}
_config_show_func() { eval declare -f "\$$1"; }

View the Developer Guide Index

View the Reference Manual Index


Generated on Tue Jul 4 17:00:18 PDT 2017 by mcsh d14 v0.21.0.