1
0
Fork 0
mirror of synced 2024-12-22 06:31:07 -05:00

Make relative_path match full dir and not just a prefix

Before this change, relative_path "/A/B/C" "/A/B/CD" would return "" instead of
the correct "../CD".
This commit is contained in:
Erik Flodin 2024-12-03 22:52:58 +01:00
parent 0b91140ea8
commit b164d03594
No known key found for this signature in database
GPG key ID: 420A7C865EE3F85F
2 changed files with 53 additions and 53 deletions

View file

@ -11,11 +11,16 @@ import pytest
("/A/B/C", "/A/B/C", ""), ("/A/B/C", "/A/B/C", ""),
("/A/B/C", "/A/B/C/D", "D"), ("/A/B/C", "/A/B/C/D", "D"),
("/A/B/C", "/A/B/C/D/E", "D/E"), ("/A/B/C", "/A/B/C/D/E", "D/E"),
("/A/B/C", "/A/B/CD", "../CD"),
("/A/B/C", "/A/BB/C", "../../BB/C"),
("/A/B/C", "/A/B/D", "../D"), ("/A/B/C", "/A/B/D", "../D"),
("/A/B/C", "/A/B/D/E", "../D/E"), ("/A/B/C", "/A/B/D/E", "../D/E"),
("/A/B/C", "/A/D", "../../D"), ("/A/B/C", "/A/D", "../../D"),
("/A/B/C", "/A/D/E", "../../D/E"), ("/A/B/C", "/A/D/E", "../../D/E"),
("/A/B/C", "/D/E/F", "../../../D/E/F"), ("/A/B/C", "/D/E/F", "../../../D/E/F"),
("/", "/A/B/C", "A/B/C"),
("/A/B/C", "/", "../../.."),
("/A/B B/C", "/A/C C/D", "../../C C/D"),
], ],
) )
def test_relative_path(runner, paths, base, full_path, expected): def test_relative_path(runner, paths, base, full_path, expected):

101
yadm
View file

@ -759,16 +759,13 @@ function alt_linking() {
} }
function ln_relative() { function ln_relative() {
local full_source full_target target_dir local source="$1"
local full_source="$1" local target="$2"
local full_target="$2"
local target_dir="${full_target%/*}"
if [ "$target_dir" == "" ]; then
target_dir="/"
fi
local rel_source local rel_source
rel_source=$(relative_path "$target_dir" "$full_source") rel_source=$(relative_path "$(builtin_dirname "$target")" "$source")
ln -nfs "$rel_source" "$full_target"
ln -nfs "$rel_source" "$target"
alt_linked+=("$rel_source") alt_linked+=("$rel_source")
} }
@ -2011,61 +2008,59 @@ function parse_encrypt() {
function builtin_dirname() { function builtin_dirname() {
# dirname is not builtin, and universally available, this is a built-in # dirname is not builtin, and universally available, this is a built-in
# replacement using parameter expansion # replacement using parameter expansion
path="$1" local path="$1"
dname="${path%/*}" while [ "${path: -1}" = "/" ]; do
if ! [[ "$path" =~ / ]]; then path="${path%/}"
echo "." done
elif [ "$dname" = "" ]; then
echo "/" local dir_name="${path%/*}"
else while [ "${dir_name: -1}" = "/" ]; do
echo "$dname" dir_name="${dir_name%/}"
done
if [ "$path" = "$dir_name" ]; then
dir_name="."
elif [ -z "$dir_name" ]; then
dir_name="/"
fi fi
echo "$dir_name"
} }
function relative_path() { function relative_path() {
# Output a path to $2/full, relative to $1/base # Output a path to $2/full, relative to $1/base
# #
# This fucntion created with ideas from # This function created with ideas from
# https://stackoverflow.com/questions/2564634 # https://stackoverflow.com/questions/2564634
base="$1" local base="$1"
full="$2" if [ "${base:0:1}" != "/" ]; then
base="$PWD/$base"
fi
common_part="$base" local full="$2"
result="" if [ "${full:0:1}" != "/" ]; then
full="$PWD/$full"
fi
count=0 local common_part="$base"
while [ "${full#"$common_part"}" == "${full}" ]; do local result=""
[ "$count" = "500" ] && return # this is a failsafe
# no match, means that candidate common part is not correct while [ "$common_part" != "$full" ]; do
# go up one level (reduce common part) if [ "$common_part" = "/" ]; then
common_part="$(builtin_dirname "$common_part")" # No common part found. Append / if result is set to make the final
# and record that we went back, with correct / handling # result correct.
if [[ -z $result ]]; then result="${result:+$result/}"
result=".." break
else elif [ "${full#"$common_part"/}" != "$full" ]; then
result="../$result" common_part="$common_part/"
fi result="${result:+$result/}"
count=$((count+1)) break
fi
# Move to parent directory and update result
common_part=$(builtin_dirname "$common_part")
result="..${result:+/$result}"
done done
if [[ $common_part == "/" ]]; then echo "$result${full#"$common_part"}"
# special case for root (no common path)
result="$result/"
fi
# since we now have identified the common part,
# compute the non-common part
forward_part="${full#"$common_part"}"
# and now stick all parts together
if [[ -n $result ]] && [[ -n $forward_part ]]; then
result="$result$forward_part"
elif [[ -n $forward_part ]]; then
# extra slash removal
result="${forward_part:1}"
fi
echo "$result"
} }
# ****** Auto Functions ****** # ****** Auto Functions ******