lib/libexec/shellspec.sh
#shellcheck shell=sh disable=SC2004,SC2016
# shellcheck source=lib/semver.sh
. "${SHELLSPEC_LIB:-./lib}/semver.sh"
# shellcheck source=lib/libexec.sh
. "${SHELLSPEC_LIB:-./lib}/libexec.sh"
load binary
use abspath starts_with escape_quote starts_with includes
pack() {
eval "set -- \"\$1\" \"\$2\" \"\${$1}\""
escape_quote "$1" "$2"
eval "$1=\"\$3 '\${$1}'\""
}
read_options_file() {
[ -e "$1" ] || return 0
file="$1" parser=$2
set --
while IFS= read -r line || [ "$line" ]; do
case $# in
0) eval "set -- $line" ;;
*) eval "set -- \"\$@\" $line" ;;
esac
done < "$file" &&:
[ $# -eq 0 ] || "$parser" "$@"
}
enum_options_file() {
callback=$1
set -- ".shellspec" ".shellspec-local"
if [ "${HOME:-}" ]; then
set -- "$HOME/.shellspec-options" "$@"
# DEPRECATED: Remove loading the $HOME/.shellspec
[ -e "$HOME/.shellspec-options" ] || set -- "$HOME/.shellspec" "$@"
fi
if [ "${XDG_CONFIG_HOME:-}" ]; then
set -- "$XDG_CONFIG_HOME/shellspec/options" "$@"
elif [ "${HOME:-}" ]; then
set -- "$HOME/.config/shellspec/options" "$@"
fi
while [ $# -gt 0 ]; do
"$callback" "$1"
shift
done
}
read_cmdline() {
[ -e "$1" ] || return 0
octal_dump < "$1" | (
cmdline='' oct_bug=''
[ "$("$SHELLSPEC_PRINTF" '\101' 2>/dev/null ||:)" = "A" ] || oct_bug=0
while IFS= read -r line; do
case $line in
000) line="040" ;;
1??) line="${oct_bug}${line}" ;;
esac
cmdline="${cmdline}\\${line}"
done
"$SHELLSPEC_PRINTF" "$cmdline"
)
}
ps_command() {
ps -f || ps
}
read_ps() {
# shellcheck disable=SC2015
ps_command 2>/dev/null | (
IFS=" " pid=$1 p=0 c=0 _pid=''
IFS= read -r line
# shellcheck disable=SC2086
set -- $line
for name in "${@:-}"; do
p=$(($p + 1))
case $name in ([pP][iI][dD]) break; esac
done
for name in "${@:-}"; do
case $name in ([cC][mM][dD] | [cC][oO][mM][mM][aA][nN][dD]) break; esac
c=$(($c + 1))
done
while IFS= read -r line; do
# shellcheck disable=SC2086
set -- $line
eval "_pid=\${$p:-}"
[ "$_pid" = "$pid" ] && shift $c && line="$*" && break
done
# workaround for old busybox ps format
case $line in (\{*) line=${line#*\} }; esac
echo "$line"
) &&: ||:
}
is_wsl() {
[ -r "$SHELLSPEC_PROC_VERSION" ] || return 1
read -r proc_version < "$SHELLSPEC_PROC_VERSION"
case $proc_version in
*[Mm]icrosoft*) return 0 ;;
*) return 1 ;;
esac
}
current_shell() {
self=$1 pid=$2
cmdline=$(read_cmdline "/proc/$2/cmdline")
[ "$cmdline" ] || cmdline=$(read_ps "$2")
# shellcheck disable=SC2295
cmdline=${cmdline%% $self*}
# workaround for OpenBSD >= 7.2 (ps -f)
case $cmdline in ([\`\|]--\ * | -\ *) cmdline=${cmdline##*\ }; esac
echo "$cmdline"
}
# shellcheck disable=SC2295
command_path() {
if [ $# -lt 2 ]; then
set -- "" "$1" "${PATH}${SHELLSPEC_PATHSEP}"
else
set -- "$1" "$2" "${PATH}${SHELLSPEC_PATHSEP}"
fi
case $2 in (*/*)
[ -x "$2" ] || return 1
[ "$1" ] && eval "$1=\"\$2\""
return 0
esac
while [ "$3" ]; do
set -- "$1" "$2" "${3#*$SHELLSPEC_PATHSEP}" "${3%%$SHELLSPEC_PATHSEP*}"
[ -x "${4%/}/$2" ] || continue
[ "$1" ] && eval "$1=\"\${4%/}/\$2\""
return 0
done
return 1
}
setup_load_path() {
set -- "$SHELLSPEC_REPORTERLIB" "$SHELLSPEC_LIB" "$SHELLSPEC_HELPERDIR"
eval "set -- \"\$@\" $SHELLSPEC_LOAD_PATH"
SHELLSPEC_LOAD_PATH=''
while [ $# -gt 0 ]; do
SHELLSPEC_LOAD_PATH="${1}${SHELLSPEC_PATHSEP}${SHELLSPEC_LOAD_PATH}"
shift
done
SHELLSPEC_LOAD_PATH=${SHELLSPEC_LOAD_PATH%"$SHELLSPEC_PATHSEP"}
}
finddirs() {
{
if [ "${2:-}" ] && is_wsl; then
# find -L is very slow on WSL
finddirs_lssort "$@"
else
finddirs_find "$@" || finddirs_lssort "$@"
fi
} 2>/dev/null || finddirs_native "$@"
}
finddirs_native() {
( set +f +u
[ "${ZSH_VERSION:-}" ] && setopt nonomatch
cd "$1" || exit
echo "."
if [ "${2:-}" ]; then
check() { [ ! -d "$i" ]; }
else
check() { [ ! -d "$i" ] || [ -L "$i" ]; }
fi
recursive() {
pwd=$1 oldpwd=$PWD
cd "$pwd" || exit
set -- *
cd "$oldpwd" || exit
for i; do set -- "$@" "$pwd/$i"; shift; done
for i; do
check "$i" && continue
i=${i#"$PWD"}
echo "$i"
recursive "$i"
done
}
recursive .
)
}
# finddirs_ls() {
# ( cd "$1"
# echo "."
# # shellcheck disable=SC2012
# ls -R ${2:+-L} . | while IFS= read -r line; do
# case $line in (./*:)
# echo "${line%:}"
# esac
# done
# )
# }
# finddirs_lsgrep() {
# ( cd "$1"
# echo "."
# # shellcheck disable=SC2010
# ls -R ${2:+-L} . | grep '^\.*/.*:$' | while IFS= read -r line; do
# echo "${line%:}"
# done
# )
# }
# finddirs_lssed() {
# ( cd "$1"
# echo "."
# # shellcheck disable=SC2012
# ls -R ${2:+-L} . | sed -n '/^\.*\/.*:$/ s/:$// p'
# )
# }
finddirs_lssort() {
( cd "$1" || exit
echo "."
# shellcheck disable=SC2012,SC2153
"$SHELLSPEC_LS" -R ${2:+-L} . | { export LC_ALL=C; "$SHELLSPEC_SORT"; } | {
while IFS= read -r line; do
case $line in (./*:) echo "${line%:}"; break; esac
done
while IFS= read -r line; do
case $line in (./*:) echo "${line%:}"; continue; esac
break
done
}
)
}
finddirs_find() {
( cd "$1" || exit
"$SHELLSPEC_FIND" ${2:+-L} . -name ".?*" -prune -o -type d -print
)
}
includes_pathstar() {
while [ $# -gt 0 ]; do
starts_with "$1" "*/" && return 0
starts_with "$1" "**/" && return 0
shift
done
return 1
}
check_pathstar() {
while [ "$1" ]; do
if starts_with "$1" "*/" || starts_with "$1" "**/"; then
set -- "${1#*/}"
continue
fi
includes "$1" '*' && return 1
return 0
done
return 1
}
expand_pathstar() {
eval "$(shift 2 && expand_pathstar_create_matcher "$@")"
# shellcheck disable=SC2034
expand_pathstar=$(shift && expand_pathstar_retrive '|||' "$@")
set -- "$IFS" "$expand_pathstar" "$1"
expand_pathstar=$3
IFS=$SHELLSPEC_LF
eval "set -- \"\$1\" \${${ZSH_VERSION:+=}2}"
IFS=$1
while [ $# -gt 1 ] && shift; do
expand_pathstar_matcher "${1%\|\|\|*}" || continue
"$expand_pathstar" "${1%\|\|\|*}" "${1##*\|\|\|}"
done
}
expand_pathstar_create_matcher() {
echo "expand_pathstar_matcher() {"
for arg; do
pattern='' doublestar=''
while :; do
if starts_with "$arg" '**/'; then
arg=${arg#*/} doublestar=1
elif starts_with "$arg" '*/'; then
arg=${arg#*/} pattern="${pattern}*/"
else
break
fi
done
escape_quote arg "$arg"
if [ "$doublestar" ]; then
echo " case \$1 in (${pattern}*)"
echo " [ \"\${1##*/}\" = '$arg' ] && return 0"
echo " esac"
elif [ "$pattern" ]; then
echo " case \$1 in (${pattern}*)"
echo " [ \"\${1#$pattern}\" = '$arg' ] && return 0"
echo " esac"
else
echo " [ \"\$1\" = '$arg' ] && return 0"
fi
echo ""
done
echo " return 1"
echo "}"
}
expand_pathstar_retrive() {
finddirs "$2" ${SHELLSPEC_DEREFERENCE:+follow} | (
sep=$1 dir=${2%"${2##*[!/]}"}
[ "$dir" = "." ] && dir="" || dir="$dir/"
shift 2
for i; do
pattern=$i
if starts_with "$i" "*/" || starts_with "$i" "**/"; then
while i=${i#*/}; do
starts_with "$i" "*/" && continue
starts_with "$i" "**/" && continue
break
done
set -- "$@" "${i}${sep}${pattern}"
else
echo "${i}${sep}"
fi
shift
done
while IFS= read -r line; do
[ "$line" = "." ] && line="$dir" || line="${dir}${line#./}/"
for i; do
echo "${line}${i}"
done
done
) | "$SHELLSPEC_SORT"
}
is_path_in_project() {
set -- "$1" "${2:-$SHELLSPEC_PROJECT_ROOT}"
[ "$1" = "$2" ] || starts_with "$1" "${2%/}/"
}
separate_abspath_and_range() {
case $3 in
[a-zA-Z]:*)
set -- "$1" "$2" "${3%%:*}" "${3#*:}"
case $4 in
*:*) set -- "$1" "$2" "$3:${4%%:*}" "${4#*:}" ;;
*) set -- "$1" "$2" "$3:$4" "" ;;
esac
;;
*)
case $3 in
*:*) set -- "$1" "$2" "${3%%:*}" "${3#*:}" ;;
*) set -- "$1" "$2" "$3" "" ;;
esac
esac
eval "$1=\$3 $2=\$4"
}
check_range() {
set -- "$1:"
while [ "$1" ] && set -- "${1#*:}" "${1%%:*}"; do
case $2 in
@*) case ${2#@} in (*[!0-9-]*) return 1; esac ;;
*) case $2 in (*[!0-9]*) return 1; esac ;;
esac
done
return 0
}
random_seed() {
# Prevent 32bit overflow
while [ ${#2} -ge 10 ]; do
set -- "$1" "${2#?}" "$3"
done
# Remove leading zeros
until [ "${2#0}" = "$2" ]; do
set -- "$1" "${2#0}" "$3"
done
# Poor random number is enough for seed
eval "$1=$(( ($2 / ($3 % 79 + 1) + $3) % 100000))"
}
kcov_version() {
command_path "$1" || return 1
error=$( { "$1" --version >/dev/null; } 2>&1) || error="error"
[ "$error" ] && return 0
"$1" --version
}
kcov_version_number() {
ver=${1:-0} && ver=${ver#"${ver%%[0-9]*}"} && ver=${ver%%[!0-9]*}
echo "$ver"
}