From d785f5db5e687bdee8b8e8372e2306248d3450b6 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Thu, 30 Dec 2021 15:49:22 +0900 Subject: [PATCH] main (ble/util/readlink): work around non-standard or missing "readlink" --- ble.pp | 139 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 32 deletions(-) diff --git a/ble.pp b/ble.pp index 46346285..5298f07a 100644 --- a/ble.pp +++ b/ble.pp @@ -131,11 +131,17 @@ function ble/restore-bash-options { _ble_init_original_IFS=$IFS IFS=$' \t\n' +_ble_bash_loaded_in_function=0 +[[ ${FUNCNAME+set} ]] && _ble_bash_loaded_in_function=1 + #------------------------------------------------------------------------------ # check environment function ble/util/print { builtin printf '%s\n' "$1"; } +# will be overwritten by src/util.sh +function ble/util/assign { builtin eval "$1=\$(builtin eval -- \"\${@:2}\")"; } + # ble/bin ## 関数 ble/bin/.default-utility-path commands... @@ -165,11 +171,11 @@ function ble/bin/.freeze-utility-path { } if ((_ble_bash>=40000)); then - function ble/bin#has { type "$@" &>/dev/null; } + function ble/bin#has { type -t "$@" &>/dev/null; } else function ble/bin#has { local cmd - for cmd; do type "$cmd" || return 1; done &>/dev/null + for cmd; do type -t "$cmd" || return 1; done &>/dev/null return 0 } fi @@ -241,43 +247,112 @@ function ble/bin/awk.use-solaris-xpg4 { } #------------------------------------------------------------------------------ +# readlink -f (Originally taken from akinomyoga/mshex.git) -_ble_bash_loaded_in_function=0 -[[ ${FUNCNAME+set} ]] && _ble_bash_loaded_in_function=1 +## @fn ble/util/readlink path +## @var[out] ret -# will be overwritten by ble-core.sh -function ble/util/assign { - builtin eval "$1=\$(builtin eval \"\${@:2}\")" -} +if ((_ble_bash>=40000)); then + _ble_util_readlink_visited_init='local -A visited=()' + function ble/util/readlink/.visited { + [[ ${visited[$1]+set} ]] && return 0 + visited[$1]=1 + return 1 + } +else + _ble_util_readlink_visited_init="local -a visited=()" + function ble/util/readlink/.visited { + local key + for key in "${visited[@]}"; do + [[ $1 == "$key" ]] && return 0 + done + visited=("$1" "${visited[@]}") + return 1 + } +fi -# readlink -f (taken from akinomyoga/mshex.git) -function ble/util/readlink { - ret= +## @fn ble/util/readlink/.readlink path +## @var[out] link +function ble/util/readlink/.readlink { local path=$1 - case "$OSTYPE" in - (cygwin|msys|linux-gnu) - # 少なくとも cygwin, GNU/Linux では readlink -f が使える - ble/util/assign ret 'PATH=/bin:/usr/bin readlink -f "$path"' ;; - (darwin*|*) - # Mac OSX には readlink -f がない。 - local PWD=$PWD OLDPWD=$OLDPWD - while [[ -h $path ]]; do - local link; ble/util/assign link 'PATH=/bin:/usr/bin readlink "$path" 2>/dev/null || true' - [[ $link ]] || break - - if [[ $link = /* || $path != */* ]]; then - # * $link ~ 絶対パス の時 - # * $link ~ 相対パス かつ ( $path が現在のディレクトリにある ) の時 - path=$link - else - local dir=${path%/*} - path=${dir%/}/$link - fi - done - ret=$path ;; + if ble/bin#has ble/bin/readlink; then + ble/util/assign link 'ble/bin/readlink -- "$path"' + [[ $link ]] + elif ble/bin#has ble/bin/ls; then + ble/util/assign link 'ble/bin/ls -ld -- "$path"' && + [[ $link == *" $path -> "?* ]] && + link=${link#*" $path -> "} + else + false + fi +} 2>/dev/null +## @fn ble/util/readlink/.resolve-physical-directory +## @var[in,out] path +function ble/util/readlink/.resolve-physical-directory { + [[ $path == */?* ]] || return 0 + local PWD=$PWD OLDPWD=$OLDPWD CDPATH= + builtin cd -L . && + local pwd=$PWD && + builtin cd -P "${path%/*}/" && + path=${PWD%/}/${path##*/} + builtin cd -L "$pwd" + return 0 +} +function ble/util/readlink/.resolve-loop { + local path=$ret + builtin eval -- "$_ble_util_readlink_visited_init" + while [[ -h $path ]]; do + local link + ble/util/readlink/.visited "$path" && break + ble/util/readlink/.readlink "$path" || break + if [[ $link == /* || $path != */* ]]; then + path=$link + else + # 相対パス ../ は物理ディレクトリ構造に従って遡る。 + ble/util/readlink/.resolve-physical-directory + path=${path%/}/$link + fi + while [[ $path == ?*/ ]]; do path=${path%/}; done + done + ret=$path +} +function ble/util/readlink/.resolve { + # 初回呼び出し時に実装を選択 + _ble_util_readlink_type= + + # より効率的な実装が可能な場合は ble/util/readlink/.resolve を独自定義。 + case $OSTYPE in + (cygwin | msys | linux-gnu) + # これらのシステムの標準 readlink では readlink -f が使える。 + # + # Note: 例えば NixOS では標準の readlink を使おうとすると問題が起こるらしい + # ので、見えている readlink を使う。見えている readlink が非標準の時は -f + # が使えるか分からないので readlink -f による実装は有効化しない。 + # + local readlink + ble/util/assign readlink 'type -P readlink' + case $readlink in + (/bin/readlink | /usr/bin/readlink) + _ble_util_readlink_type=readlink-f + builtin eval "function ble/util/readlink/.resolve { ble/util/assign ret '$readlink -f -- \"\$ret\"'; }" ;; + esac ;; esac + + if [[ ! $_ble_util_readlink_type ]]; then + _ble_util_readlink_type=loop + ble/bin/.freeze-utility-path readlink ls + function ble/util/readlink/.resolve { ble/util/readlink/.resolve-loop; } + fi + + ble/util/readlink/.resolve +} +function ble/util/readlink { + ret=$1 + if [[ -h $ret ]]; then ble/util/readlink/.resolve; fi } +#--------------------------------------- + function ble/base/.create-user-directory { local var=$1 dir=$2 if [[ ! -d $dir ]]; then