Files
Pmodules/Pmodules/libstd.bash
T

341 lines
7.2 KiB
Bash

#!/bin/bash
#
# logging/message functions
#
std::log() {
local -ri fd=$1
local -r fmt="$2"
shift 2
printf -- "${fmt}" "$@" 1>&$fd
printf -- "\n" 1>&$fd
}
std::info() {
std::log 2 "$1" "${@:2}"
}
std::error() {
std::log 2 "$1" "${@:2}"
}
std::debug() {
[[ -v PMODULES_DEBUG ]] || return 0
std::log 2 "$@"
}
std::die() {
local -ri ec=$1
shift
if [[ -n $@ ]]; then
local -r fmt=$1
shift
std::log 2 "$fmt" "$@"
fi
exit $ec
}
std::def_cmds(){
local path="$1"
shift
for cmd in "$@"; do
eval declare -gr ${cmd}=$(PATH="${path}" /usr/bin/which $cmd 2>/dev/null)
if [[ -z "${!cmd}" ]]; then
std::die 255 "${cmd} not found"
fi
done
}
#
# get answer to yes/no question
#
# $1: prompt
#
std::get_YN_answer() {
local -r prompt="$1"
local ans
read -p "${prompt}" ans
case ${ans} in
y|Y )
return 0;;
* )
return 1;;
esac
}
#
# return normalized abolute pathname
# $1: filename
std::get_abspath() {
local -r fname=$1
#[[ -r "${fname}" ]] || return 1
if [[ -d ${fname} ]]; then
echo $(cd "${fname}" && pwd)
else
local -r dname=$(dirname "${fname}")
echo $(cd "${dname}" && pwd)/$(basename "${fname}")
fi
}
std::append_path () {
local -nr P="$1"
shift 1
local dir
local dirs=''
for dir in "$@"; do
[[ "${P}" == @(|*:)${dir}@(|:*) ]] && continue
dirs+=":${dir}"
done
if [[ -z ${P} ]]; then
P="${dirs:1}" # remove leading ':'
else
P="${P}${dirs}"
fi
}
std::prepend_path () {
local -nr P="$1"
shift 1
local dir
local dirs=''
for dir in "$@"; do
[[ "${P}" == @(|*:)${dir}@(|:*) ]] && continue
dirs+="${dir}:"
done
if [[ -z ${P} ]]; then
P="${dirs:0:-1}" # remove trailing ':'
else
P="${dirs}${P}"
fi
}
std::remove_path() {
local -nr P="$1"
shift 1
local -ar dirs="$@"
local new_path=''
local -r _P=( ${P//:/ } )
local dir=''
for dir in "${dirs[@]}"; do
# loop over all entries in path
for entry in "${_P[@]}"; do
[[ "${entry}" != "${dir}" ]] && new_path+=":${entry}"
done
done
P="${new_path:1}" # remove leading ':'
}
#
# Replace or remove a directory in a path variable.
#
# To remove a dir:
# std::replace_path PATH <pattern>
#
# To replace a dir:
# std::replace_path PATH <pattern> /replacement/path
#
# Args:
# $1 name of the shell variable to set (e.g. PATH)
# $2 a grep pattern identifying the element to be removed/replaced
# $3 the replacement string (use "" for removal)
#
# Based on solution published here:
# https://stackoverflow.com/questions/273909/how-do-i-manipulate-path-elements-in-shell-scripts
#
std::replace_path () {
local -r path="$1"
local -r removepat="$2"
local -r replacestr="$3"
local -r removestr=$(echo "${!path}" | tr ":" "\n" | grep -m 1 "^$removepat\$")
export $path="$(echo "${!path}" | tr ":" "\n" | sed "s:^${removestr}\$:${replacestr}:" |
sed '/^\s*$/d' | tr "\n" ":" | sed -e 's|^:||' -e 's|:$||')"
}
#
# Functions to split a path into its components.
#
# Args:
# $1 upvar
# $2 absolute or relative path (depends on the function)
# $3 opt upvar: number of components
#
# Notes:
# std::split_path()
# if the path is absolute, the first element of the returned array is empty.
#
# std::split_abspath()
# the path must begin with a slash, otherwise std::die() is called with
# an internal error message.
#
# std::split_relpath()
# analog to std::split_abspath() with a relative path.
#
std::split_path() {
local -n parts="$1"
local -r path="$2"
IFS='/'
local std__split_path_result=( ${std__split_path_tmp} )
unset IFS
parts="${std__split_path_result[@]}"
if (( $# >= 3 )); then
# return number of parts
local -n num="$3"
num="${#std__split_path_result[@]}"
fi
}
std::split_abspath() {
local -n parts="$1"
local -r path="$2"
if [[ "${path:0:1}" == '/' ]]; then
local -r std__split_path_tmp="${path:1}"
else
std::die 255 "Oops: Internal error in '${FUNCNAME[0]}' called by '${FUNCNAME[1]}' }"
fi
IFS='/'
local std__split_path_result=( ${std__split_path_tmp} )
unset IFS
parts="${std__split_path_result[@]}"
if (( $# >= 3 )); then
# return number of parts
local -n num="$3"
num="${#std__split_path_result[@]}"
fi
}
std::split_relpath() {
local -n parts="$1"
local -r path="$2"
if [[ "${path:0:1}" == '/' ]]; then
std::die 255 "Oops: Internal error in '${FUNCNAME[0]}' called by '${FUNCNAME[1]}' }"
else
local -r std__split_path_tmp="${path}"
fi
IFS='/'
local std__split_path_result=( ${std__split_path_tmp} )
unset IFS
parts="${std__split_path_result[@]}"
if (( $# >= 3 )); then
# return number of parts
local -n num="$3"
num="${#std__split_path_result[@]}"
fi
}
std::read_versions() {
local -r fname="$1"
local varname=''
while read _name _version; do
[[ -z ${_name} ]] && continue
[[ -z ${_version} ]] && continue
[[ "${_name:0:1}" == '#' ]] && continue
var_name=$(echo ${_name} | tr [:lower:] [:upper:])_VERSION
# don't set version, if already set
if [[ -z ${!var_name} ]]; then
eval ${var_name}="${_version}"
fi
done < "${fname}"
}
std.get_os_release_linux() {
#local lsb_release=$(which lsb_release)
local ID=''
local VERSION_ID=''
if [[ -n $(which lsb_release 2>/dev/null) ]]; then
ID=$(lsb_release -is)
VERSION_ID=$(lsb_release -rs)
elif [[ -r '/etc/os-release' ]]; then
source /etc/os-release
else
std::die 4 "Cannot determin OS release!\n"
fi
case "${ID,,}" in
redhatenterpriseserver | redhatenterprise | scientific | springdale | rhel | centos | fedora )
echo "rhel${VERSION_ID%%.*}"
;;
ubuntu )
echo "Ubuntu${VERSION_ID%.*}"
;;
* )
echo "Unknown"
exit 1
;;
esac
}
std.get_os_release_macos() {
VERSION_ID=$(sw_vers -productVersion)
echo "macOS${VERSION_ID%.*}"
}
std::get_os_release() {
local -A func_map;
func_map['Linux']=std.get_os_release_linux
func_map['Darwin']=std.get_os_release_macos
${func_map[$(uname -s)]}
}
std::get_type() {
local -a signature=$(typeset -p "$1")
case ${signature[1]} in
-Ai* )
echo 'int dict'
;;
-A* )
echo 'dict'
;;
-ai* )
echo 'int array'
;;
-a* )
echo 'array'
;;
-i* )
echo 'integer'
;;
-- )
echo 'string'
;;
* )
echo 'none'
return 1
esac
}
std::parse_yaml() {
#
# parse a YAML file
# See: https://gist.github.com/pkuczynski/8665367
#
local -r fname="$1"
local -r prefix="$2"
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "${fname}" |
awk -F$fs '{
indent = length($1)/2;
vname[indent] = $2;
for (i in vname) {
if (i > indent) {delete vname[i]}
}
if (length($3) > 0) {
vn="";
for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3);
}
}'
}
# Local Variables:
# mode: sh
# sh-basic-offset: 8
# tab-width: 8
# End: