-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathuninstall.sh
More file actions
executable file
·155 lines (132 loc) · 3.97 KB
/
Copy pathuninstall.sh
File metadata and controls
executable file
·155 lines (132 loc) · 3.97 KB
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
#!/usr/bin/env bash
#
# uninstall.sh - Reverse what install.sh did.
#
# For each mapping, if the destination is a symlink pointing back into this
# repo it is removed. Then, if the most-recent backup directory
# (~/.dotfiles-backup/latest) holds the original file, it is moved back
# into place. Anything we did not create or back up is left alone.
#
# Usage:
# ./uninstall.sh remove symlinks and restore latest backup
# ./uninstall.sh --dry-run print what would happen without changing anything
# ./uninstall.sh --help show this help text
set -euo pipefail
DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKUP_ROOT="${DOTFILES_BACKUP_DIR:-$HOME/.dotfiles-backup}"
LATEST_LINK="$BACKUP_ROOT/latest"
DRY_RUN=0
# shellcheck source=lib/links.sh
source "$DOTFILES_DIR/lib/links.sh"
c_reset='\033[0m'
c_dim='\033[2m'
c_red='\033[0;31m'
c_green='\033[0;32m'
c_yellow='\033[0;33m'
c_blue='\033[0;34m'
log() { printf '%b\n' "$*"; }
info() { log "${c_blue}[*]${c_reset} $*"; }
ok() { log "${c_green}[+]${c_reset} $*"; }
warn() { log "${c_yellow}[!]${c_reset} $*"; }
err() { log "${c_red}[x]${c_reset} $*" >&2; }
skip() { log " ${c_dim}skip:${c_reset} $*"; }
usage() {
sed -n '2,/^$/p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
}
run() {
if (( DRY_RUN )); then
log " ${c_dim}dry-run:${c_reset} $*"
else
"$@"
fi
}
for arg in "$@"; do
case "$arg" in
-n|--dry-run) DRY_RUN=1 ;;
-h|--help) usage; exit 0 ;;
*) err "unknown argument: $arg"; usage; exit 2 ;;
esac
done
if (( DRY_RUN )); then
warn "dry-run mode: no filesystem changes will be made"
fi
# Resolve the backup directory we should restore from. The "latest" symlink
# is written by install.sh after each run; if it is missing we degrade
# gracefully and only remove our symlinks.
BACKUP_DIR=""
if [[ -L "$LATEST_LINK" ]]; then
BACKUP_DIR="$(readlink "$LATEST_LINK")"
# readlink may return a relative path on some platforms; normalize.
if [[ "$BACKUP_DIR" != /* ]]; then
BACKUP_DIR="$BACKUP_ROOT/$BACKUP_DIR"
fi
info "restoring from: $BACKUP_DIR"
elif [[ -d "$BACKUP_ROOT" ]]; then
warn "no $LATEST_LINK pointer; will not restore backups"
else
warn "no backups found under $BACKUP_ROOT; will only remove symlinks"
fi
unlink_if_ours() {
local rel_src="$1" rel_dst="$2"
local src="$DOTFILES_DIR/$rel_src"
local dst="$HOME/$rel_dst"
if [[ -L "$dst" ]]; then
local current
current="$(readlink "$dst")"
if [[ "$current" == "$src" ]]; then
run rm "$dst"
ok "removed symlink ~/$rel_dst"
return 0
fi
skip "~/$rel_dst is a symlink we did not create"
return 1
fi
if [[ -e "$dst" ]]; then
skip "~/$rel_dst is not a symlink we created"
return 1
fi
skip "~/$rel_dst absent"
return 0
}
restore_backup() {
local rel_dst="$1"
local dst="$HOME/$rel_dst"
local src="$BACKUP_DIR/$rel_dst"
[[ -z "$BACKUP_DIR" ]] && return 0
if [[ ! -e "$src" && ! -L "$src" ]]; then
skip "no backup for ~/$rel_dst"
return 0
fi
if [[ -e "$dst" || -L "$dst" ]]; then
warn "~/$rel_dst still occupied; leaving backup at $src"
return 0
fi
local parent
parent="$(dirname "$dst")"
if [[ ! -d "$parent" ]]; then
run mkdir -p "$parent"
fi
run mv "$src" "$dst"
ok "restored ~/$rel_dst from backup"
}
for entry in "${LINKS[@]}"; do
src="${entry%%:*}"
dst="${entry#*:}"
if unlink_if_ours "$src" "$dst"; then
restore_backup "$dst"
fi
done
# Clean up the now-empty timestamped backup dir (if every file was restored).
if [[ -n "$BACKUP_DIR" && -d "$BACKUP_DIR" ]] && ! (( DRY_RUN )); then
if find "$BACKUP_DIR" -mindepth 1 -print -quit | grep -q .; then
info "backup retained (some files remain): $BACKUP_DIR"
else
rmdir "$BACKUP_DIR" 2>/dev/null || true
# The "latest" symlink now dangles - remove it if it points at the gone dir.
if [[ -L "$LATEST_LINK" ]] && [[ ! -e "$LATEST_LINK" ]]; then
rm "$LATEST_LINK"
fi
ok "removed empty backup dir"
fi
fi
ok "uninstall complete"