From 465ad6ab006b64818c05a6798b3c36e6ec0df576 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Fri, 11 Nov 2016 14:52:41 +0300 Subject: bugfix & refactoring --- update.sh | 192 +++++++++++++++++++++++++++++--------------------------------- 1 file changed, 91 insertions(+), 101 deletions(-) diff --git a/update.sh b/update.sh index 3c2b0fd..c61b07c 100755 --- a/update.sh +++ b/update.sh @@ -60,7 +60,7 @@ dump() { done } -resolve_path() { +traverse_path() { local -a paths local exit_with_usage= @@ -68,6 +68,8 @@ resolve_path() { local type_flag= local type_name= + local fmt='%s\n' + while [ "$#" -gt 0 ]; do local key="$1" shift @@ -77,6 +79,9 @@ resolve_path() { exit_with_usage=0 break ;; + -z|-0|--zero) + fmt='%s\0' + ;; --) break ;; @@ -115,6 +120,7 @@ resolve_path() { while IFS= read -d '' -r path; do if [ -n "$must_exist" ] && [ ! -e "$path" ]; then dump "must exist: $path" >&2 + return 1 fi if [ -e "$path" ] && [ -n "$type_flag" ] && ! test "$type_flag" "$path"; then @@ -122,7 +128,7 @@ resolve_path() { return 1 fi - echo "$path" + printf -- "$fmt" "$path" done < <( readlink -z --canonicalize-missing -- ${paths[@]+"${paths[@]}"} ) } @@ -149,22 +155,32 @@ resolve_variable() { fi local var_path="${!var_name}" - resolve_path --exist --directory -- "$var_path" + traverse_path --exist --directory -- "$var_path" } cache_variable() { local var_name for var_name; do + [ -n "${cached_paths[$var_name]+x}" ] && continue cached_paths[$var_name]="$( resolve_variable "$var_name" )" done } -check_symlinks_enabled() { - if is_cygwin; then - check_symlinks_enabled_cygwin - else - return 0 - fi +readonly var_name_regex='%\([_[:alpha:]][_[:alnum:]]*\)%' + +extract_variable_name() { + local s + for s; do + local var_name + var_name="$( expr "$s" : "$var_name_regex/" )" + + if [ -z "$var_name" ]; then + dump "couldn't extract variable name from: $s" >&2 + return 1 + fi + + echo "$var_name" + done } # Shared directory settings @@ -178,7 +194,7 @@ update_shared_dir() { fi local new_shared_dir - new_shared_dir="$( resolve_path --exist --directory -- "$1" )" + new_shared_dir="$( traverse_path --exist --directory -- "$1" )" [ "$db_path" == "$shared_dir/$default_db_fn" ] \ && db_path="$new_shared_dir/$default_db_fn" @@ -198,12 +214,12 @@ update_database_path() { return 1 fi - db_path="$( resolve_path --file -- "$1" )" + db_path="$( traverse_path --file -- "$1" )" mkdir -p -- "$( dirname -- "$db_path" )" } ensure_database_exists() { - [ -f "$db_path" ] || is_dry_run || touch "$db_path" + [ -f "$db_path" ] || is_dry_run || > "$db_path" } read_database() { @@ -216,10 +232,7 @@ read_database() { } write_database() { - if is_dry_run; then - dump "won't write the database because it's a dry run" - return 0 - fi + is_dry_run && return 0 > "$db_path" @@ -235,21 +248,13 @@ delete_obsolete_dirs() { return 1 fi + is_dry_run && return 0 + local base_dir="$1" local dir="$2" - if [ ! -d "$base_dir" ]; then - dump "base directory doesn't exist: $base_dir" >&2 - return 1 - fi - - if [ ! -d "$dir" ]; then - dump "directory doesn't exist: $dir" >&2 - return 1 - fi - - base_dir="$( resolve_path --exist --directory -- "$base_dir" )" - dir="$( resolve_path --exist --directory -- "$dir" )" + base_dir="$( traverse_path --exist --directory -- "$base_dir" )" + dir="$( traverse_path --exist --directory -- "$dir" )" [ "$base_dir" == "$dir" ] && return 0 @@ -261,136 +266,113 @@ delete_obsolete_dirs() { return 1 fi - if is_dry_run; then - dump "won't delete the directory because it's a dry run" - return 0 - fi - ( cd "$base_dir" && rmdir -p --ignore-fail-on-non-empty -- "$subpath" ) } -readonly var_name_regex='%\([_[:alpha:]][_[:alnum:]]*\)%' - -extract_variable_name() { - local s - for s; do - local var_name - var_name="$( expr "$s" : "$var_name_regex/" )" - - if [ -z "$var_name" ]; then - dump "couldn't extract variable name from: $s" >&2 - return 1 - fi - - echo "$var_name" - done -} - delete_obsolete_entries() { local entry for entry in "${!database[@]}"; do dump "entry: $entry" + unset -v 'database[$entry]' local var_name - if ! var_name="$( extract_variable_name "$entry" )"; then - unset -v 'database[$entry]' - continue - fi + var_name="$( extract_variable_name "$entry" )" || continue cache_variable "$var_name" local symlink_var_dir - if ! symlink_var_dir="$( resolve_variable "$var_name" )"; then - unset -v 'database[$entry]' - continue - fi + symlink_var_dir="$( resolve_variable "$var_name" )" || continue local shared_var_dir="$shared_dir/%$var_name%" - local subpath="${entry#%$var_name%/}" - local symlink_path="$symlink_var_dir/$subpath" local shared_path="$shared_var_dir/$subpath" - if [ ! -e "$shared_path" ]; then - dump " missing source file: $shared_path" >&2 + dump " shared file path: $shared_path" + dump " symlink path: $symlink_path" + + if [ ! -L "$shared_path" ] && [ ! -e "$shared_path" ]; then + dump ' the shared file is missing, so going to delete the symlink' + is_dry_run && continue if [ ! -L "$symlink_path" ]; then - dump " not a symlink, so won't delete: $symlink_path" - elif is_dry_run; then - dump " won't delete an obsolete symlink, because it's a dry run" - else - rm -f -- "$symlink_path" + dump " not a symlink or doesn't exist, so won't delete" + continue + fi - local symlink_dir - symlink_dir="$( dirname -- "$symlink_path" )" + local target_path + target_path="$( traverse_path -- "$symlink_path" )" - delete_obsolete_dirs "$symlink_var_dir" "$symlink_dir" || true + if [ "$shared_path" != "$target_path" ]; then + dump " doesn't point to the shared file, so won't delete" + continue fi - unset -v 'database[$entry]' + rm -f -- "$symlink_path" + + local symlink_dir + symlink_dir="$( dirname -- "$symlink_path" )" + + delete_obsolete_dirs "$symlink_var_dir" "$symlink_dir" || true continue fi - if [ ! -L "$symlink_path" ] || [ ! -e "$symlink_path" ]; then - dump " not a symlink or doesn't exist: $symlink_path" >&2 - unset -v 'database[$entry]' + if [ ! -L "$symlink_path" ]; then + dump " not a symlink or doesn't exist" continue fi local target_path - target_path="$( resolve_path -- "$symlink_path" )" + target_path="$( traverse_path -- "$symlink_path" )" if [ "$target_path" != "$shared_path" ]; then - dump " points to a wrong file: $symlink_path" >&2 - unset -v 'database[$entry]' + dump " doesn't point to the shared file" continue fi - dump ' ... points to the right file' + dump ' ... points to the shared file' + database[$entry]=1 done } discover_new_entries() { local shared_var_dir while IFS= read -d '' -r shared_var_dir; do - dump "source directory: $shared_var_dir" + dump "shared directory: $shared_dir/$shared_var_dir" local var_name - var_name="$( basename -- "$shared_var_dir" )" - var_name="$( expr "$var_name" : "$var_name_regex" )" - dump " variable name: $var_name" + var_name="$( extract_variable_name "$shared_var_dir" )" cache_variable "$var_name" + shared_var_dir="$shared_dir/$shared_var_dir" + local symlink_var_dir - if ! symlink_var_dir="$( resolve_variable "$var_name" )"; then - continue - fi - dump " destination directory: $symlink_var_dir" + symlink_var_dir="$( resolve_variable "$var_name" )" || continue + dump " symlinks directory: $symlink_var_dir" local shared_path while IFS= read -d '' -r shared_path; do - dump " source file: $shared_path" + dump " shared file path: $shared_path" - local entry="%$var_name%${shared_path:${#shared_var_dir}}" + local entry="%$var_name%/${shared_path:${#shared_var_dir}}" if [ -n "${database[$entry]+x}" ]; then - dump ' ... points to the right file' + dump ' ... already has a symlink' continue fi - local symlink_path="$symlink_var_dir${shared_path:${#shared_var_dir}}" - dump " destination file: $symlink_path" + local subpath="${shared_path:${#shared_var_dir}}" + local symlink_path="$symlink_var_dir/$subpath" - if is_dry_run; then - dump " won't create a symlink because it's a dry run" - else - mkdir -p -- "$( dirname -- "$symlink_path" )" - ln -f -s -- "$shared_path" "$symlink_path" - fi + dump " symlink path: $symlink_path" + + is_dry_run && continue + + mkdir -p -- "$( dirname -- "$symlink_path" )" + ln -f -s --no-target-directory -- "$shared_path" "$symlink_path" database[$entry]=1 done < <( find "$shared_var_dir" -type f -print0 ) - done < <( find "$shared_dir" -regextype posix-basic -mindepth 1 -maxdepth 1 -type d -regex ".*/$var_name_regex\$" -print0 ) + done < <( find "$shared_dir" -regextype posix-basic -mindepth 1 -maxdepth 1 -type d -regex ".*/$var_name_regex\$" -printf '%P/\0' ) } # Main routines @@ -429,14 +411,14 @@ parse_script_options() { ;; *) - dump "usage error: unrecognized parameter: $key" >&2 + dump "unrecognized parameter: $key" >&2 exit_with_usage=1 break ;; esac if [ "$#" -eq 0 ]; then - dump "usage error: missing argument for parameter: $key" >&2 + dump "missing argument for parameter: $key" >&2 exit_with_usage=1 break fi @@ -454,7 +436,7 @@ parse_script_options() { ;; *) - dump "usage error: unrecognized parameter: $key" >&2 + dump "unrecognized parameter: $key" >&2 exit_with_usage=1 break ;; @@ -466,6 +448,14 @@ is_dry_run() { test -n "${dry_run+x}" } +check_symlinks_enabled() { + if is_cygwin; then + check_symlinks_enabled_cygwin + else + return 0 + fi +} + main() { parse_script_options "$@" [ -n "${exit_with_usage+x}" ] && exit_with_usage -- cgit v1.2.3