aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rwxr-xr-xlinks-chmod5
-rwxr-xr-xlinks-remove5
-rwxr-xr-xlinks-update5
-rw-r--r--src/db.sh19
-rw-r--r--src/path.sh4
-rwxr-xr-xtest/test.sh104
7 files changed, 90 insertions, 56 deletions
diff --git a/README.md b/README.md
index 18d3838..2ff362c 100644
--- a/README.md
+++ b/README.md
@@ -93,10 +93,10 @@ In this example, symlinks to files in "../src" must appear in "/test/dest".
For my personal real-life usage examples, see
-* my [Linux/Cygwin environment],
+* [my dotfiles],
* configuration files for various [Windows apps].
-[Linux/Cygwin environment]: https://github.com/egor-tensin/linux-home
+[my dotfiles]: https://github.com/egor-tensin/linux-home
[Windows apps]: https://github.com/egor-tensin/windows-home
Limitations
diff --git a/links-chmod b/links-chmod
index 9810cf6..f722b95 100755
--- a/links-chmod
+++ b/links-chmod
@@ -7,9 +7,8 @@
# usage: ./links-chmod [-h|--help] [-d|--database PATH] [-s|--shared-dir DIR] [-n|--dry-run] MODE
-set -o errexit
-set -o nounset
-set -o pipefail
+set -o errexit -o nounset -o pipefail
+shopt -s inherit_errexit lastpipe
script_name="$( basename -- "${BASH_SOURCE[0]}" )"
readonly script_name
diff --git a/links-remove b/links-remove
index ea79596..c378485 100755
--- a/links-remove
+++ b/links-remove
@@ -7,9 +7,8 @@
# usage: ./links-remove [-h|--help] [-d|--database PATH] [-s|--shared-dir DIR] [-n|--dry-run]
-set -o errexit
-set -o nounset
-set -o pipefail
+set -o errexit -o nounset -o pipefail
+shopt -s inherit_errexit lastpipe
script_name="$( basename -- "${BASH_SOURCE[0]}" )"
readonly script_name
diff --git a/links-update b/links-update
index 6a802bc..5b15f1b 100755
--- a/links-update
+++ b/links-update
@@ -19,9 +19,8 @@
# usage: ./links-update [-h|--help] [-d|--database PATH] [-s|--shared-dir DIR] [-m|--mode MODE] [-n|--dry-run]
-set -o errexit
-set -o nounset
-set -o pipefail
+set -o errexit -o nounset -o pipefail
+shopt -s inherit_errexit lastpipe
script_name="$( basename -- "${BASH_SOURCE[0]}" )"
readonly script_name
diff --git a/src/db.sh b/src/db.sh
index b057202..201ad25 100644
--- a/src/db.sh
+++ b/src/db.sh
@@ -57,7 +57,7 @@ add_entry() {
local shared_var_dir="$shared_root_dir%$var_name%"
local symlink_var_dir
symlink_var_dir="$( resolve_variable "$var_name" )"
- local subpath="${entry#%$var_name%/}"
+ local subpath="${entry#%"$var_name"%/}"
local shared_path="$shared_var_dir"
[ "$shared_var_dir" != / ] && shared_path="$shared_path/"
@@ -134,7 +134,7 @@ delete_obsolete_dirs() {
[ "$base_dir" = "$dir" ] && return 0
- local subpath="${dir##$base_dir/}"
+ local subpath="${dir##"$base_dir"/}"
if [ "$subpath" = "$dir" ]; then
dump "base directory: $base_dir" >&2
@@ -193,10 +193,18 @@ shared_file_present() {
link_all_entries() {
local shared_var_dir
+
+ find "$shared_root_dir" \
+ -mindepth 1 -maxdepth 1 \
+ -\( -type d -o -type l -\) \
+ -regextype posix-basic \
+ -regex ".*/$var_name_regex\$" \
+ -printf '%P\0' |
while IFS= read -d '' -r shared_var_dir; do
dump "shared directory: $shared_root_dir$shared_var_dir"
-
local shared_path
+
+ find "$shared_root_dir$shared_var_dir/" -\( -type f -o -type l -\) -print0 |
while IFS= read -d '' -r shared_path; do
dump " shared file path: $shared_path"
local entry="${shared_path:${#shared_root_dir}}"
@@ -214,9 +222,8 @@ link_all_entries() {
dump ' ... adding a symlink'
is_dry_run || link_entry "$entry"
fi
-
- done < <( find "$shared_root_dir$shared_var_dir/" -\( -type f -o -type l -\) -print0 )
- done < <( find "$shared_root_dir" -regextype posix-basic -mindepth 1 -maxdepth 1 -\( -type d -o -type l -\) -regex ".*/$var_name_regex\$" -printf '%P\0' )
+ done
+ done
}
unlink_all_entries() {
diff --git a/src/path.sh b/src/path.sh
index bf52a6f..8ac71a9 100644
--- a/src/path.sh
+++ b/src/path.sh
@@ -76,7 +76,7 @@ traverse_path() {
local -a abs_paths=()
local path
- while IFS= read -d '' -r path; do
+ readlink -z --canonicalize-missing -- ${paths[@]+"${paths[@]}"} | while IFS= read -d '' -r path; do
if [ -n "$must_exist" ] && [ ! -e "$path" ]; then
dump "must exist: $path" >&2
return 1
@@ -88,7 +88,7 @@ traverse_path() {
fi
abs_paths+=("$path")
- done < <( readlink -z --canonicalize-missing -- ${paths[@]+"${paths[@]}"} )
+ done
printf -- "$fmt" ${abs_paths[@]+"${abs_paths[@]}"}
}
diff --git a/test/test.sh b/test/test.sh
index 0e02480..f2abfde 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail
+shopt -s inherit_errexit lastpipe
script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
script_dir="$( cd -- "$script_dir" && pwd )"
@@ -25,6 +26,7 @@ test_alt_dest_dir=
new_test() {
local test_name=
[ "${#FUNCNAME[@]}" -gt 1 ] && test_name="${FUNCNAME[1]}"
+ [ "$#" -gt 0 ] && test_name="$1"
echo
echo ======================================================================
@@ -54,14 +56,14 @@ call_bin_script() {
printf -- '\n'
echo
- DEST="$test_dest_dir" ALT_DEST="$test_alt_dest_dir" eval "$@" --shared-dir "$test_src_dir" --database "$test_root_dir/links.bin"
+ DEST="$test_dest_dir" ALT_DEST="$test_alt_dest_dir" "$@" --shared-dir "$test_src_dir" --database "$test_root_dir/links.bin"
}
call_update() {
call_bin_script "$script_dir/../links-update" "$@"
}
-call_unlink() {
+call_remove() {
call_bin_script "$script_dir/../links-remove"
}
@@ -126,7 +128,8 @@ verify_mode() {
}
test_update_works() {
- # Basic test to make sure update.sh actually creates the proper symlinks.
+ # Basic test to make sure that links-update actually creates the proper
+ # symlinks.
new_test
call_update
@@ -143,19 +146,20 @@ $test_dest_dir/foo/2.txt->$test_src_dir/%DEST%/foo/2.txt"
verify_output "$expected_output"
}
-test_unlink_works() {
- # Basic test to make sure unlink.sh actually removes the created symlinks.
+test_remove_works() {
+ # Basic test to make sure links-remove actually removes the created
+ # symlinks.
new_test
call_update
- call_unlink
+ call_remove
local expected_output="$test_dest_dir->"
verify_output "$expected_output"
}
-test_unlink_does_not_overwrite_files() {
- # Check that if a user overwrites a symlink with his own file, unlink.sh
+test_remove_does_not_overwrite_files() {
+ # Check that if a user overwrites a symlink with his own file, links-remove
# keeps it.
new_test
@@ -165,7 +169,7 @@ test_unlink_does_not_overwrite_files() {
rm -- "$test_dest_dir/bar/3.txt"
echo 'User content' > "$test_dest_dir/bar/3.txt"
- call_unlink
+ call_remove
# 3.txt must be kept:
local expected_output="$test_dest_dir->
@@ -175,16 +179,39 @@ $test_dest_dir/bar/3.txt->"
verify_output "$expected_output"
}
-test_dir_symlink_update_works() {
- # We can symlink files to multiple directories by creating symlinks inside
- # --shared-dir.
+test_remove_does_not_delete_used_dirs() {
+ # Check that if a user adds a file to a destination directory, it's not
+ # deleted by links-remove.
new_test
+ call_update
+
+ # User adds his own file to the directory:
+ echo 'User content' > "$test_dest_dir/bar/my-file"
+
+ call_remove
+
+ # bar/ and bar/my-file must be kept:
+ local expected_output="$test_dest_dir->
+$test_dest_dir/bar->
+$test_dest_dir/bar/my-file->"
+
+ verify_output "$expected_output"
+}
+
+new_test_dir_symlink() {
+ new_test "${FUNCNAME[1]}"
# Files will get symlinks in the directory pointed to by $DEST, as well as
# by $ALT_DEST.
ln -s -- '%DEST%' "$test_src_dir/%ALT_DEST%"
+}
+test_dir_symlink_update_works() {
+ # We can symlink files to multiple directories by creating symlinks inside
+ # --shared-dir.
+
+ new_test_dir_symlink
call_update
local expected_output="$test_dest_dir->
@@ -210,17 +237,12 @@ $test_alt_dest_dir/foo/2.txt->$test_src_dir/%ALT_DEST%/foo/2.txt"
verify_output "$expected_output" "$test_alt_dest_dir"
}
-test_dir_symlink_unlink_works() {
- # Test that unlink.sh works for directory symlinks inside --shared-dir.
-
- new_test
-
- # Files will get symlinks in the directory pointed to by $DEST, as well as
- # by $ALT_DEST.
- ln -s -- '%DEST%' "$test_src_dir/%ALT_DEST%"
+test_dir_symlink_remove_works() {
+ # Test that links-remove works for directory symlinks inside --shared-dir.
+ new_test_dir_symlink
call_update
- call_unlink
+ call_remove
local expected_output="$test_dest_dir->"
verify_output "$expected_output"
@@ -232,9 +254,9 @@ test_dir_symlink_unlink_works() {
test_dir_symlink_remove_shared_file() {
# If we remove a shared file, both of the symlinks should be removed.
- new_test
- ln -s -- '%DEST%' "$test_src_dir/%ALT_DEST%"
+ new_test_dir_symlink
call_update
+
# Remove a random shared file:
rm -- "$test_src_dir/%DEST%/bar/3.txt"
call_update
@@ -264,9 +286,9 @@ test_dir_symlink_remove_dir_symlink() {
# If we remove a directory symlink in --shared-dir, all the symlinks
# accessible through this directory symlink should be removed.
- new_test
- ln -s -- '%DEST%' "$test_src_dir/%ALT_DEST%"
+ new_test_dir_symlink
call_update
+
# Remove the directory symlink:
rm -- "$test_src_dir/%ALT_DEST%"
call_update
@@ -286,12 +308,17 @@ $test_dest_dir/foo/2.txt->$test_src_dir/%DEST%/foo/2.txt"
verify_output "$expected_output" "$test_alt_dest_dir"
}
-test_symlink_update_works() {
- # Shared files can also be symlinks, pointing to something else.
+new_test_symlink() {
+ new_test "${FUNCNAME[1]}"
- new_test
# Create a stupid symlink.
ln -s -- 'bar/3.txt' "$test_src_dir/%DEST%/3_copy.txt"
+}
+
+test_symlink_update_works() {
+ # Shared files can also be symlinks, pointing to something else.
+
+ new_test_symlink
call_update
local expected_output="$test_dest_dir->
@@ -318,12 +345,12 @@ $test_dest_dir/foo/2.txt->$test_src_dir/%DEST%/foo/2.txt"
test "$copy_content" = '3'
}
-test_symlink_unlink_works() {
- new_test
- # Create a stupid symlink.
- ln -s -- 'bar/3.txt' "$test_src_dir/%DEST%/3_copy.txt"
+test_symlink_remove_works() {
+ # Verify that links-remove doesn't delete shared symlinks.
+
+ new_test_symlink
call_update
- call_unlink
+ call_remove
local expected_output="$test_dest_dir->"
verify_output "$expected_output"
@@ -342,6 +369,7 @@ test_symlink_unlink_works() {
test_chmod_works() {
# Test that links-chmod works.
+
new_test
call_update
@@ -365,6 +393,7 @@ $test_dest_dir/foo/2.txt->$test_src_dir/%DEST%/foo/2.txt"
test_update_chmod() {
# Test that links-update --mode works.
+
new_test
local expected_mode='0622'
call_update --mode "$expected_mode"
@@ -384,16 +413,17 @@ $test_dest_dir/foo/2.txt->$test_src_dir/%DEST%/foo/2.txt"
main() {
test_update_works
- test_unlink_works
- test_unlink_does_not_overwrite_files
+ test_remove_works
+ test_remove_does_not_overwrite_files
+ test_remove_does_not_delete_used_dirs
test_dir_symlink_update_works
- test_dir_symlink_unlink_works
+ test_dir_symlink_remove_works
test_dir_symlink_remove_shared_file
test_dir_symlink_remove_dir_symlink
test_symlink_update_works
- test_symlink_unlink_works
+ test_symlink_remove_works
test_chmod_works
test_update_chmod