-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstall.sh
executable file
·147 lines (131 loc) · 3.61 KB
/
install.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
#!/bin/bash
# This file's name
__self="$(basename "${BASH_SOURCE[0]}")"
# Full path of this file's directory
__dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# File name extension for backed up files
ext_bak=dotsave
# By default links are installed in user's home directory
install_dir=$HOME
# $1 exit code
# $2 error msg
function errexit {
echo "Error: $2" 1>&2
exit "$1"
}
function cleanup {
_IFS=$IFS; IFS=$'\n'
dotsave_files=($(find "$install_dir" -xdev -name "*.$ext_bak"))
IFS=$_IFS
for f in "${dotsave_files[@]}"; do
if [ "${f##*.}" = "$ext_bak" ]; then
rm "$f"
echo "Deleted $f"
else
errexit 1 "'$f' is not a $ext_bak file!"
fi
done
}
function is_leaf_dir {
[ -z "$(find "$1" -maxdepth 1 ! -path "$1" -type d)" ]
}
export -f is_leaf_dir
function get_leaf_dirs_ntfs {
find "$__dir" \
-not \( \
-path "$__dir/.git" \
-prune \
\) \
-type d \
\( \
-empty \
-o \
-exec sh -c 'is_leaf_dir "$1"' _ '{}' \; \
\) \
-print
}
# Get dirs without children (only links to parent and itself). Prune content of
# .git directory and exclude .git itself. Otherwise it will be found if it has
# no subdirectories.
function get_leaf_dirs_unix {
find "$__dir" \
-not \( \
-path "$__dir/.git" \
-prune \
\) \
-type d \
-links 2
}
# Parse key value pairs
while [ $# -gt 0 ]; do
key="$1"
case $key in
-C|--directory)
install_dir="${2%/}"
[ -d "$install_dir" ] \
|| errexit $? "'$install_dir' is not a directory!"
shift
;;
--owner)
owner="$2"
getent passwd "$owner" > /dev/null \
|| errexit $? "user '$owner' does not exist!"
shift
;;
--group)
group="$2"
getent group "$group" > /dev/null \
|| errexit $? "group '$group' does not exist!"
shift
;;
-c|--clean)
do_clean=true
;;
*)
# unknown
esac
shift
done
# If clear switch set, remove backed up files
[ "$do_clean" = true ] && cleanup && exit 0
_IFS=$IFS; IFS=$'\n'
if df -t ntfs "$__dir" > /dev/null 2>&1; then
leaf_dirs=($(get_leaf_dirs_ntfs))
else
leaf_dirs=($(get_leaf_dirs_unix))
fi
# Get file names. Ignore this file, README.md, TODO and files in .git directory
dotfiles=($(find "$__dir" -type f ! -name "$__self" ! -name README.md ! -name TODO -not -path "$__dir/.git/*"))
IFS=$_IFS
echo 'Ensuring directory structure...'
for d in "${leaf_dirs[@]}"; do
name=$install_dir/${d#$__dir/}
mkdir -p "$name"
# set permission on directories
if [ -n "$owner" ] || [ -n "$group" ]; then
# 'owner:' sets owner and login group, so:
owned=$owner; [ -z "$group" ] || owned+=:$group
while true; do
chown "$owned" "$name"
name=$(dirname "$name")
[ "$name" != "$install_dir" ] || break
done
fi
done
echo 'Setting up symlinks...'
for f in "${dotfiles[@]}"; do
name=$install_dir/${f#$__dir/}
# Save existing files
if [ -f "$name" ]; then
bak=${name}.${ext_bak}
while [ -f "$bak" ]; do
bak=${bak}.${ext_bak}
done
mv "$name" "$bak"
echo "warning: '$name' saved as '$bak'"
fi
ln -sv "$f" "$name"
# Fix permission on link (don't dereference)
[ -z "$owner" ] || chown -h "$owner" "$name"
[ -z "$group" ] || chgrp -h "$group" "$name"
done