Skip to content

Commit

Permalink
Merge pull request #1221 from akinomyoga/load-path
Browse files Browse the repository at this point in the history
fix: source files using absolute paths for absolute BASH_SOURCE
  • Loading branch information
scop authored Nov 13, 2024
2 parents 0e7a0cf + d599dcf commit cb6e5d0
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 20 deletions.
49 changes: 31 additions & 18 deletions bash_completion
Original file line number Diff line number Diff line change
Expand Up @@ -2190,15 +2190,22 @@ _comp_compgen_fstypes()
_comp_abspath()
{
REPLY=$1
case $REPLY in
/*) ;;
../*) REPLY=$PWD/${REPLY:3} ;;
*) REPLY=$PWD/$REPLY ;;
esac
while [[ $REPLY == */./* ]]; do
REPLY=${REPLY//\/.\//\/}
done
[[ $REPLY == /* ]] || REPLY=$PWD/$REPLY
REPLY=${REPLY//+(\/)/\/}
while true; do
# Process "." and "..". To avoid reducing "/../../ => /", we convert
# "/*/../" one by one. "/.." at the beginning is ignored. Then, /*/../
# in the middle is processed. Finally, /*/.. at the end is removed.
case $REPLY in
*/./*) REPLY=${REPLY//\/.\//\/} ;;
*/.) REPLY=${REPLY%/.} ;;
/..?(/*)) REPLY=${REPLY#/..} ;;
*/+([^/])/../*) REPLY=${REPLY/\/+([^\/])\/..\//\/} ;;
*/+([^/])/..) REPLY=${REPLY%/+([^/])/..} ;;
*) break ;;
esac
done
[[ $REPLY ]] || REPLY=/
}

# Get real command.
Expand Down Expand Up @@ -3141,6 +3148,18 @@ _comp_complete_minimal()
# https://lists.gnu.org/archive/html/bug-bash/2012-01/msg00045.html
complete -F _comp_complete_minimal ''
# Initialize the variable "_comp__base_directory"
# @var[out] _comp__base_directory
_comp__init_base_directory()
{
local REPLY
_comp_abspath "${BASH_SOURCE[0]-./bash_completion}"
_comp__base_directory=${REPLY%/*}
[[ $_comp__base_directory ]] || _comp__base_directory=/
unset -f "$FUNCNAME"
}
_comp__init_base_directory
# @since 2.12
_comp_load()
{
Expand Down Expand Up @@ -3193,11 +3212,7 @@ _comp_load()
# we want to prefer in-tree completions over ones possibly coming with a
# system installed bash-completion. (Due to usual install layouts, this
# often hits the correct completions in system installations, too.)
if [[ $BASH_SOURCE == */* ]]; then
dirs+=("${BASH_SOURCE%/*}/completions")
else
dirs+=(./completions)
fi
dirs+=("$_comp__base_directory/completions")
# 3) From bin directories extracted from the specified path to the command,
# the real path to the command, and $PATH
Expand Down Expand Up @@ -3339,12 +3354,10 @@ _comp__init_collect_startup_configs()
# run-in-place-from-git-clone setups. Notably we do it after the
# system location here, in order to prefer in-tree variables and
# functions.
if [[ ${base_path%/*} == */share/bash-completion ]]; then
compat_dir=${base_path%/share/bash-completion/*}/etc/bash_completion.d
elif [[ $base_path == */* ]]; then
compat_dir="${base_path%/*}/bash_completion.d"
if [[ $_comp__base_directory == */share/bash-completion ]]; then
compat_dir=${_comp__base_directory%/share/bash-completion}/etc/bash_completion.d
else
compat_dir=./bash_completion.d
compat_dir=$_comp__base_directory/bash_completion.d
fi
[[ ${compat_dirs[0]} == "$compat_dir" ]] ||
compat_dirs+=("$compat_dir")
Expand Down
130 changes: 128 additions & 2 deletions test/t/unit/test_unit_abspath.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_relative(self, bash, functions):
)
assert output.strip().endswith("/shared/foo/bar")

def test_cwd(self, bash, functions):
def test_cwd1(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester ./foo/./bar",
Expand All @@ -55,7 +55,34 @@ def test_cwd(self, bash, functions):
)
assert output.strip().endswith("/shared/foo/bar")

def test_parent(self, bash, functions):
def test_cwd2(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /.",
want_output=True,
want_newline=False,
)
assert output.strip() == "/"

def test_cwd3(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /foo/.",
want_output=True,
want_newline=False,
)
assert output.strip() == "/foo"

def test_cwd4(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /././.",
want_output=True,
want_newline=False,
)
assert output.strip() == "/"

def test_parent1(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester ../shared/foo/bar",
Expand All @@ -65,3 +92,102 @@ def test_parent(self, bash, functions):
assert output.strip().endswith(
"/shared/foo/bar"
) and not output.strip().endswith("../shared/foo/bar")

def test_parent2(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /foo/..",
want_output=True,
want_newline=False,
)
assert output.strip() == "/"

def test_parent3(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /..",
want_output=True,
want_newline=False,
)
assert output.strip() == "/"

def test_parent4(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /../foo/bar",
want_output=True,
want_newline=False,
)
assert output.strip() == "/foo/bar"

def test_parent5(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /../../foo/bar",
want_output=True,
want_newline=False,
)
assert output.strip() == "/foo/bar"

def test_parent6(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /foo/../bar",
want_output=True,
want_newline=False,
)
assert output.strip() == "/bar"

def test_parent7(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /foo/../../bar",
want_output=True,
want_newline=False,
)
assert output.strip() == "/bar"

def test_parent8(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /dir1/dir2/dir3/../dir4/../../foo",
want_output=True,
want_newline=False,
)
assert output.strip() == "/dir1/foo"

def test_parent9(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester //dir1/dir2///../foo",
want_output=True,
want_newline=False,
)
assert output.strip() == "/dir1/foo"

def test_parent10(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /dir1/dir2/dir3/..",
want_output=True,
want_newline=False,
)
assert output.strip() == "/dir1/dir2"

def test_parent11(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /dir1/dir2/dir3/../..",
want_output=True,
want_newline=False,
)
assert output.strip() == "/dir1"

def test_parent12(self, bash, functions):
output = assert_bash_exec(
bash,
"__tester /dir1/dir2/dir3/../../../..",
want_output=True,
want_newline=False,
)
assert output.strip() == "/"

0 comments on commit cb6e5d0

Please sign in to comment.