Skip to content

Commit

Permalink
sstephensonGH-184: Fix link resolution for bats
Browse files Browse the repository at this point in the history
This rewrites the old logic a bit by using `type -p`, `readlink -m`  and
on boxes where we don't have coreutils like `readlink` we use `realpath`
to figure out the correct installation directory of bats.

Also fixes GH#182

Signed-off-by: Wesley Schwengle <wesley@schwengle.net>
  • Loading branch information
waterkip authored and sublimino committed Apr 27, 2020
1 parent 0af2f36 commit 433db67
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 31 deletions.
77 changes: 53 additions & 24 deletions bin/bats
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,71 @@
set -e

BATS_READLINK='true'
BATS_REALPATH=''
if command -v 'greadlink' >/dev/null; then
BATS_READLINK='greadlink'
elif command -v 'readlink' >/dev/null; then
BATS_READLINK='readlink'
fi

bats_resolve_absolute_root_dir() {
local cwd="$PWD"
local path="$1"
local result="$2"
local target_dir
local target_name
local original_shell_options="$-"

# Resolve the parent directory, e.g. /bin => /usr/bin on CentOS (#113).
set -P
set +e
if ! $BATS_READLINK -m $0 &>/dev/null; then
BATS_REALPATH='realpath'
fi
set -e

while true; do
target_dir="${path%/*}"
target_name="${path##*/}"
resolve_path() {
local path_to_bats=$1
local target_path;

if [[ "$target_dir" != "$path" ]]; then
cd "$target_dir"
if [[ -L "$path_to_bats" ]]; then
# Busybox has no readlink from coreutils
if [[ ! -z "$BATS_REALPATH" ]]; then
target_path="$("$BATS_REALPATH" "$path_to_bats")"
# we need to traverse the paths
target_path="$(dirname "$target_path")" # strip bats
target_path="$(dirname "$target_path")" # strip bin
else
target_path="$("$BATS_READLINK" -m "$path_to_bats/../../")"
fi

if [[ -L "$target_name" ]]; then
path="$("$BATS_READLINK" "$target_name")"
elif [[ -f "$path_to_bats" ]]; then
target_path=$(dirname "$path_to_bats");
if [[ ! -z "$BATS_REALPATH" ]]; then
target_path="$("$BATS_REALPATH" "$target_path")"
else
target_path="$("$BATS_READLINK" -m "$target_path")"
fi
target_path="$(dirname "$target_path")" # strip bin
elif [[ -d $path_to_bats ]]; then
if [[ ! -z "$BATS_REALPATH" ]]; then
target_path="$("$BATS_REALPATH" "$path_to_bats")"
target_path="$(dirname "$target_path")"
else
printf -v "$result" -- '%s' "${PWD%/*}"
set +P "-$original_shell_options"
cd "$cwd"
return
target_path="$("$BATS_READLINK" -m "$path_to_bats/../")"
fi
done
fi

echo "$target_path";
}

bats_resolve_absolute_root_dir() {
local cwd="$PWD"
local path_to_bats="$1"
local result="$2"
local target_path

if [[ "$path_to_bats" = $(basename $1) ]] ; then
path_to_bats=$(type -p "$path_to_bats")
fi

target_path="$(resolve_path $path_to_bats)"
if [[ "$target_path" == '.' ]];
then
target_path="$(resolve_path "$target_path")"
fi
printf -v "$result" -- '%s' "$target_path"
}

export BATS_ROOT
bats_resolve_absolute_root_dir "$0" 'BATS_ROOT'
exec "$BATS_ROOT/libexec/bats-core/bats" "$@"
exec env BATS_ROOT="$BATS_ROOT" "$BATS_ROOT/libexec/bats-core/bats" "$@"
38 changes: 31 additions & 7 deletions test/root.bats
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,52 @@ setup() {

# The resolution scheme here is:
#
# Set in setup
# - /bin => /usr/bin (relative directory)
# - /usr/bin/foo => /usr/bin/bar (relative executable)
# - /usr/bin/bar => /opt/bats/bin0/bar (absolute executable)
# - /opt/bats/bin0 => /opt/bats/bin1 (relative directory)
# - /opt/bats/bin1 => /opt/bats/bin2 (absolute directory)
# - /opt/bats/bin2/bar => /opt/bats-core/bin/bar (absolute executable)
# - /opt/bats-core/bin/bar => /opt/bats-core/bin/baz (relative executable)
# - /opt/bats-core/bin/baz => /opt/bats-core/bin/bats (relative executable)
@test "set BATS_ROOT with extreme symlink resolution" {
cd "$BATS_TEST_SUITE_TMPDIR"
mkdir -p "opt/bats/bin2"

# - /usr/bin/foo => /usr/bin/bar (relative executable)
ln -s bar usr/bin/foo
# - /usr/bin/bar => /opt/bats/bin0/bar (absolute executable)
ln -s "$BATS_TEST_SUITE_TMPDIR/opt/bats/bin0/bar" usr/bin/bar
# - /opt/bats/bin0 => /opt/bats/bin1 (relative directory)
ln -s bin1 opt/bats/bin0
# - /opt/bats/bin1 => /opt/bats/bin2 (absolute directory)
ln -s "$BATS_TEST_SUITE_TMPDIR/opt/bats/bin2" opt/bats/bin1
# - /opt/bats/bin2/bar => /opt/bats-core/bin/bar (absolute executable)
ln -s "$BATS_TEST_SUITE_TMPDIR/opt/bats-core/bin/bar" opt/bats/bin2/bar
# - /opt/bats-core/bin/bar => /opt/bats-core/bin/baz (relative executable)
ln -s baz opt/bats-core/bin/bar
# - /opt/bats-core/bin/baz => /opt/bats-core/bin/bats (relative executable)
ln -s bats opt/bats-core/bin/baz

cd - >/dev/null
run "$BATS_TEST_SUITE_TMPDIR/bin/foo" -v
[ "$status" -eq 0 ]
[ "${output%% *}" == 'Bats' ]
}

@test "set BATS_ROOT when calling from same dir" {
cd "$BATS_TEST_SUITE_TMPDIR"
run ./bin/bats -v
[ "$status" -eq 0 ]
[ "${output%% *}" == 'Bats' ]
}

@test "set BATS_ROOT from PATH" {
cd /tmp
PATH="$PATH:$BATS_TEST_SUITE_TMPDIR/bin"
run bats -v
[ "$status" -eq 0 ]
[ "${output%% *}" == 'Bats' ]
}

@test "#182 and probably #184 as well" {
cd /tmp
PATH="$PATH:$BATS_TEST_SUITE_TMPDIR/bin"
run bash bats -v
[ "$status" -eq 0 ]
[ "${output%% *}" == 'Bats' ]
}

0 comments on commit 433db67

Please sign in to comment.