mirror of
https://github.com/Pmodules/Pmodules.git
synced 2026-06-24 00:27:59 +02:00
341 lines
7.2 KiB
Bash
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:
|