neechbear / dotfiles

Selectively symlink your .rcfiles stored in a combined common folder (like a Git repository).
https://nicolaw.uk/dotfiles
MIT License
3 stars 1 forks source link

Installation issues on MacOS #1

Open weakcamel opened 6 years ago

weakcamel commented 6 years ago

When following the installation instructions from README.md on a MacOS machine (High Sierra), the last script which attempts to symlink the scripts hangs and needs to be interrrupted:

git clone https://github.com/neechbear/dotfiles.git
dotfiles/bin/dotfiles.sh install
dotfiles/bin/dotfiles-symlink-files dotfiles/ ~

Problem seems to be coming from the loop in relative_path() function which enters an infinite loop:

https://github.com/neechbear/dotfiles/blob/74ee56b253eb1df367f42e7c1760b4a9ff217e1f/bin/dotfiles.sh#L310

weakcamel commented 6 years ago

Bash version:

$ bash --version
GNU bash, version 4.4.23(1)-release (x86_64-apple-darwin17.5.0)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Excerpt from the log:

...
+++ relative_path /Users/USER/bin dotfiles/bin
 ++++ readlink -m /Users/USER/bin
 ++++ args=()
 ++++ declare -A args
 ++++ declare arg
 ++++ for arg in "$@"
 ++++ [[ -m = \-\- ]]
 ++++ [[ - = \- ]]
 ++++ shift
 ++++ args["${arg:1}"]=1
 ++++ for arg in "$@"
 ++++ [[ /Users/USER/bin = \-\- ]]
 ++++ [[ / = \- ]]
 ++++ [[ -z /Users/USER/bin ]]
 ++++ [[ -h /Users/USER/bin ]]
 ++++ [[ ! -e /Users/USER/bin ]]
 ++++ echo /Users/USER/bin
 +++ declare src=/Users/USER/bin
 ++++ readlink -m dotfiles/bin
 ++++ args=()
 ++++ declare -A args
 ++++ declare arg
 ++++ for arg in "$@"
 ++++ [[ -m = \-\- ]]
 ++++ [[ - = \- ]]
 ++++ shift
 ++++ args["${arg:1}"]=1
 ++++ for arg in "$@"
 ++++ [[ dotfiles/bin = \-\- ]]
 ++++ [[ d = \- ]]
 ++++ [[ -z dotfiles/bin ]]
 ++++ [[ -h dotfiles/bin ]]
 ++++ [[ ! -e dotfiles/bin ]]
 ++++ echo dotfiles/bin
 +++ declare tgt=dotfiles/bin
 +++ [[ -z /Users/USER/bin ]]
 +++ [[ -z dotfiles/bin ]]
 +++ declare common_part=/Users/USER/bin
 +++ declare result=
 +++ [[ dotfiles/bin == \d\o\t\f\i\l\e\s\/\b\i\n ]]
 +++ common_part=/Users/USER
 +++ [[ -z /Users/USER ]]
 +++ [[ -z '' ]]
 +++ result=..
 +++ [[ dotfiles/bin == \d\o\t\f\i\l\e\s\/\b\i\n ]]
 +++ common_part=/Users
 +++ [[ -z /Users ]]
 +++ [[ -z .. ]]
 +++ result=../..
 +++ [[ dotfiles/bin == \d\o\t\f\i\l\e\s\/\b\i\n ]]
 +++ common_part=
 +++ [[ -z '' ]]
 +++ common_part=/
 +++ [[ -z ../.. ]]
 +++ result=../../..
 +++ [[ dotfiles/bin == \d\o\t\f\i\l\e\s\/\b\i\n ]]
...
# and so the fun begins
weakcamel commented 6 years ago

I tried to check if adding a guardian to the loop helps, but not really; the result turned out to be a broken symlink

$ git diff
@@ -294,6 +294,9 @@ symlink_files () {
         declare force=1
       fi
       ln ${force:+-f} -v -s ${_df_ln_args:-} "$relative_link_target" "$link_name"
+      if ! [[ -e "$link_name" ]]; then
+          >&2 echo "WARNING: installed symlink pointing to a non-existing location (${link_name})"
+      fi
     fi
   done < <(normalised_files "$path")
 }
@@ -315,7 +318,7 @@ relative_path () {

   declare common_part="$src" # for now
   declare result="" # for now
-  while [[ "${tgt#$common_part}" == "$tgt" ]] ; do
+  while [[ "${tgt#$common_part}" == "$tgt" ]] && [[ $common_part != "/"  ]]; do
     # No match, means that candidate common part is not correct.
     # Go up one level (reduce common part).
     common_part="${common_part%/*}"

The output is:

$ dotfiles/bin/dotfiles-symlink-files dotfiles/ ~
/Users/USER/bin/dotfiles-file-weights -> ../../../dotfiles/bin/dotfiles-file-weights
WARNING: installed symlink pointing to a non-existing location (/Users/USER/bin/dotfiles-file-weights)
/Users/USER/bin/dotfiles-available-identities -> ../../../dotfiles/bin/dotfiles-available-identities
WARNING: installed symlink pointing to a non-existing location (/Users/USER/bin/dotfiles-available-identities)
/Users/USER/bin/dotfiles-symlink-files -> ../../../dotfiles/bin/dotfiles-symlink-files
WARNING: installed symlink pointing to a non-existing location (/Users/USER/bin/dotfiles-symlink-files)
/Users/USER/bin/dotfiles-file-identities -> ../../../dotfiles/bin/dotfiles-file-identities
WARNING: installed symlink pointing to a non-existing location (/Users/USER/bin/dotfiles-file-identities)
/Users/USER/bin/dotfiles-normalised-files -> ../../../dotfiles/bin/dotfiles-normalised-files
WARNING: installed symlink pointing to a non-existing location (/Users/USER/bin/dotfiles-normalised-files)
/Users/USER/bin/dotfiles-best-file -> ../../../dotfiles/bin/dotfiles-best-file
WARNING: installed symlink pointing to a non-existing location (/Users/USER/bin/dotfiles-best-file)
/Users/USER/bin/dotfiles.sh -> ../../../dotfiles/bin/dotfiles.sh
WARNING: installed symlink pointing to a non-existing location (/Users/USER/bin/dotfiles.sh)
weakcamel commented 6 years ago

As advised, the "offending" function was tested with absolute paths as well and the result is .. better.

$ relative_path /Users/USER/bin dotfiles/bin
../../../dotfiles/bin
$ relative_path /Users/USER/bin $PWD/dotfiles/bin
../git/dotfiles/bin

The issue might be related to the fact that readlink -f on Mac OS is an option for format string...

$ readlink -f dotfiles/bin/dotfiles.sh 
dotfiles/bin/dotfiles.sh

$ man readlink

STAT(1)                   BSD General Commands Manual                  STAT(1)

NAME
     readlink, stat -- display file status
…
     -f format
             Display information using the specified format.  See the FORMATS section for a descrip-
             tion of valid formats.