-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootstrap.sh
executable file
·167 lines (139 loc) · 3.75 KB
/
bootstrap.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/env bash
set -euo pipefail
print_help() {
cat <<EOF
Create symlinks in your home directory that point to files in this repository.
Will not overwrite existing files.
-n dry-run: show what would be done
-h help: show this help and exit
EOF
}
die() {
>&2 echo "fatal: $1"
exit 1
}
find_paths() {
# see comment about karabiner below
find \
. \
\! \( -name ".git" -type d -prune \) \
\! \( -name "init" -type d -prune \) \
\! \( -name "karabiner" -type d -prune \) \
\! -name "." \
\! -name ".DS_Store" \
\! -name "bootstrap.sh" \
\! -name "brew.sh" \
\! -name "find_bootstrap.sh" \
\! -name "macos.sh" \
\! -name "vim.sh" \
\! -name "Brewfile" \
\! -name "README.md" \
\! -name "*.swp" \
\! -name ".gitignore" \
-type "$1" \
-print0
}
check_file() {
local -r DEST_FILE="$HOME/$1"
# if the file doesn't exist, we're good
if ! [[ -e "$DEST_FILE" ]]; then
return 0
fi
# if the file is a symlink and the symlink's target is exactly $DEST_FILE
if [[ -h "$DEST_FILE" &&
$(readlink "$DEST_FILE") == "$PWD/$1" ]]; then
# then it's already correct and doesn't need linking
return 0
fi
# else it exists and is incorrect! don't overwrite
return 1
}
process_dir() {
local -r DEST_DIR="$HOME/$1"
if [[ -d "$DEST_DIR" ]]; then
# already exists
return
fi
if [[ $DRY_RUN ]]; then
echo "would mkdir $DEST_DIR"
return
fi
echo "making dir $DEST_DIR"
mkdir -p "$DEST_DIR"
}
process_file() {
local -r DEST_FILE="$HOME/$1"
# if the file is a symlnk and the symlink's target is exactly $DEST_FILE
if [[ -h "$DEST_FILE" &&
$(readlink "$DEST_FILE") == "$PWD/$1" ]]; then
# then it's already correct and doesn't need linking
return
fi
if [[ -e "$DEST_FILE" ]]; then
# it exists and isn't a symlink or doesn't point to the right place
# already. this should have been caught in check_file, but never hurts
# to be paranoid.
die "unexpected file exists after check_file"
fi
if [[ $DRY_RUN ]]; then
echo "would link $DEST_FILE -> $PWD/$1"
return
fi
echo "linking $DEST_FILE -> $PWD/$1"
ln -s "$PWD/$1" "$DEST_FILE"
}
cd "$(dirname "${BASH_SOURCE}")"
DRY_RUN=
FORCE=
while getopts ':nh' OPT; do
case "$OPT" in
n)
DRY_RUN=1
;;
h)
print_help
exit 0
;;
\?) # without \, would match any single character
print_help
die "illegal option $OPTARG"
;;
esac
done
DIRS_ARR=()
TO_LINK_ARR=()
# read null-delimited directory names from find -print0 into DIRS_ARR
while IFS= read -r -d '' DIR; do
# remove leading './'
DIR="${DIR:2}"
DIRS_ARR+=("$DIR")
done < <(find_paths d)
while IFS= read -r -d '' FILE; do
# remove leading './'
FILE="${FILE:2}"
TO_LINK_ARR+=("$FILE")
done < <(find_paths f)
# karabiner overwrites its configuration file, and so its directory must be
# symlinked instead. sigh.
# https://github.com/tekezo/Karabiner-Elements/issues/1284
TO_LINK_ARR+=(".config/karabiner")
CHECK_RESULT=
for FILE in "${TO_LINK_ARR[@]}"; do
if ! check_file "$FILE"; then
CHECK_RESULT=1
echo "file already exists: $HOME/$FILE"
fi
done
if [[ $CHECK_RESULT ]]; then
if [[ $DRY_RUN ]]; then
echo "would refuse to overwrite one or more files"
exit 0
fi
die "refusing to overwrite one or more files"
fi
for DIR in "${DIRS_ARR[@]}"; do
process_dir "$DIR"
done
for FILE in "${TO_LINK_ARR[@]}"; do
process_file "$FILE"
done