-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsetup.sh
executable file
·236 lines (209 loc) · 6.17 KB
/
setup.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#!/usr/bin/env bash
DOTFILES_DEBUG=${DOTFILES_DEBUG:-$DOTFILES_PRETEND}
DOTFILES_DIR=${DOTFILES_DIR:-~/.dotfiles}
DOTFILES_REPO=${DOTFILES_REPO:[email protected]:behaghel/dotfiles.git}
BRANCH=${BRANCH:-master}
setup_dir_name="._setup"
[ -n "$DOTFILES_DEBUG" ] && set -x
log() {
$silent || echo $@
}
command_exists() {
command -v "$@" >> /dev/null 2>&1
}
export -f command_exists
restart_shell=""
abilities=$(find $DOTFILES_DIR -maxdepth 1 -type d -not \( -name "$(basename $DOTFILES_DIR)" -o -name "$setup_dir_name" -o -name ".*" \) -exec basename {} ';')
has_systemd=$([ $(command_exists systemctl) ] && systemctl; echo $?)
failed_checkout() {
echo "Failed to git clone $1"
exit -1
}
reload_context() {
for i in "$HOME"/.config/profile.d/*.profile; do
source $i
done
}
export -f reload_context
checkout() {
command_exists git || install_ability git
git clone --branch "$BRANCH" "$1" "$2" || failed_checkout "$1"
}
run_if_exists() {
if [ -x $1 ]; then
([ -n "$DOTFILES_PRETEND" -a "$2" != "verify" ] && echo "Simulation: $1") || $1
else
true # stay truthy even when no executable was run
fi
}
hook_file() {
echo "$DOTFILES_DIR/$1/$setup_dir_name/$2.sh"
}
run_hook() {
local hook=$(hook_file $1 $2)
if [ "$2" == 'verify' -a -n "$DOTFILES_FORCE" ]; then
false
elif [ "$2" == 'verify' -a ! -x $hook ]; then
command_exists $1 && echo "command $1 exists already"
# default verification: check is command named like the ability exists
else
run_if_exists $hook $2
fi
}
read_list_from_file() {
# allow several item on one line (sep by space) and allow commenting out a line with #
cat $1 | egrep -v '^#' | sed 's/[ \t]*#.*$//' | sed 's/ /\n/g'
}
export -f read_list_from_file
is_ability() {
#TODO: ankify bash tests and array membership and predicate functions and find
local re="\\b$1\\b"
[[ "$abilities" =~ $re ]] && echo "$1"
}
is_ansible_role() {
echo "$1" | awk -F: '$1 ~ "ansible" {print $2}'
}
install_deps() {
#TODO: allow for different dependencies on linux vs macos
local needs=$DOTFILES_DIR/$1/$setup_dir_name/needs
[ -f $needs ] && \
local deps=( $(read_list_from_file $needs) ) && \
[ -n "$deps" ] && installit $1 "${deps[@]}"
}
install_fonts() {
local fonts_file=$DOTFILES_DIR/$1/$setup_dir_name/fonts
[ -f $fonts_file ] && \
local fonts=( $(read_list_from_file $fonts_file) ) || return 0
local_fonts_dir=$HOME/.local/share/fonts
mkdir -p $local_fonts_dir 2> /dev/null
pushd $local_fonts_dir
# install apps available to local users and root
local font
local font_url
for font_url in ${fonts[@]}; do
wget $font_url
font=$(basename $font_url)
[[ "$font" == *zip ]] && unzip $font
rm $(basename $font)
done
popd
}
prepit() {
( [ "$1" == "." ] || git submodule update --init "$1" )
install_deps $1
install_fonts $1
run_hook $1 "pre"
}
stowit() {
# -v verbose
# -n DOTFILES_PRETEND but don't do anything
# -R recursive
# -t target
# we treat "." as an ability but we don't stow it for obvious reasons
[ "$1" = "." ] || \
stow -v${DOTFILES_PRETEND:+ -n} -R -t ${HOME} --no-folding --ignore ${setup_dir_name} $1
}
wrapit() {
# if $DOTFILES_DIR/$1/.config/profile.d/ not empty, then reload shell
[ -d "$DOTFILES_DIR/$1/.config/profile.d/" ] && \
reload_context && restart_shell=true
provides=$DOTFILES_DIR/$1/$setup_dir_name/provides
[ -f $provides ] && [ $has_systemd -eq 0 ] &&\
local services=( $(read_list_from_file $provides) ) && \
systemctl --user daemon-reload && \
for service in ${services[@]}; do
if [ -z "$DOTFILES_PRETEND" ]; then
systemctl --user enable $service
systemctl --user start $service
else
echo "Simulation: activation of $service through systemctl"
fi
done
run_hook $1 "post" || exit -5
echo "$1 is ready."
}
ensure_ansible() {
command_exists ansible-playbook || {
install_ability ansible && reload_context
}
}
playbook() {
ensure_ansible
# -K ask for sudo password
# -b become sudo
# -i [file] inventory (prepackage with only localhost)
ansible-playbook -K -b${DOTFILES_PRETEND:+ --syntax-check} -i $DOTFILES_DIR/._setup/ansible/hosts "$1" && rm "$1"
}
install_ansible() {
ensure_ansible
tmpfile=$(mktemp)
echo -ne "---\n- hosts: all\n roles:\n" >> "$tmpfile"
for role in "${1[@]}"; do
ansible-galaxy install "$role"
echo " - $role" >> "$tmpfile"
done
playbook "$tmpfile"
}
install_package() {
local apps=$@
local i
log "install package $apps"
tmpfile=$(mktemp)
echo -ne "---\n- hosts: all\n tasks:\n - name: Install $apps\n package:\n state: present\n name:\n" >> "$tmpfile"
for i in $@; do
echo " - $i" >> "$tmpfile"
done
playbook "$tmpfile"
}
noop() {
echo "nothing to install";
exit -1;
}
install_ability() {
local abis=( $@ )
[ ${#abis[@]} -gt 0 ] || noop
local i
for i in "${abis[@]}"; do
run_hook $i "verify" || {
prepit $i && stowit $i && wrapit $i;
}
done
}
installit() {
[ -n $1 ] || noop
local requester=$1
shift
local install_list=( "$@" )
local abilities_to_install=()
local ansible_roles=()
local packages=()
local i
for i in "${install_list[@]}"; do
local ansible_role=$(is_ansible_role $i)
local ability=$(is_ability $i)
if [[ $i = $requester ]]; then
# ability $1 has a dependency of the same name, stop the infinite loop
packages+=( $requester )
elif [ -n "$ansible_role" ]; then
ansible_roles+=( $ansible_role )
elif [ -n "$ability" ]; then
abilities_to_install+=( $ability )
else
packages+=( $i )
fi
done
[[ ${#ansible_roles[@]} -gt 0 ]] && install_ansible ${ansible_roles[@]}
[[ ${#abilities_to_install[@]} -gt 0 ]] && install_ability ${abilities_to_install[@]}
[[ ${#packages[@]} -gt 0 ]] && install_package ${packages[@]}
}
main(){
#install_ability "." &&
[ $# -gt 0 ] && installit '_root_' "$@"
#TODO: have a help printed when no arguments
#FIXME: restart_shell seems to get set in a subshell…
# indeed one level of {} doesn't create subshell but any deeper
# level will… unbelievable
[ -n "$restart_shell" ] && \
echo "Restarting $SHELL to update config..." && \
exec $SHELL
}