-
Notifications
You must be signed in to change notification settings - Fork 1
/
dotlink
executable file
·130 lines (100 loc) · 3.08 KB
/
dotlink
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
#!/usr/bin/env bash
# Text formatting variables
text_bold="\e[1m"
text_red="\e[31m"
text_reset="\e[0m"
text_yellow="\e[33m"
# Output functions
function log {
echo -ne "$1\n"
}
function warning {
echo -ne "${text_bold}${text_yellow}WARNING${text_reset} $1\n"
}
function error {
echo -ne "${text_bold}${text_red}ERROR${text_reset} $1\n"
exit 1
}
function print_usage {
cat <<EOF
Usage: dotlink [OPTIONS]
Link all files from hosts/\$HOSTNAME to \$HOME.
OPTIONS
-h, --help Show this help message and exit
-u, --unlink Remove current links
EOF
exit
}
# Set default values
unlink=false
# Parse arguments
while (( "$#" )); do
case "$1" in
-h|--help)
print_usage
;;
-u|--unlink)
unlink=true
shift
;;
-*)
error "Unsupported flag: $1"
;;
*)
error "Unsupported argument: $1"
;;
esac
done
# Get hostname of this machine and filter out hostnames of subdomains like .local
hostname="$(hostname)"
hostname="${hostname%%.*}"
# Get current dotfile directory for later linking
dotfiles="$(dirname "$(realpath "$0")")"
# Check if dotfiles for host exist
if [ ! -d "${dotfiles}/hosts/${hostname}" ]; then
error "No dotfiles for host ${text_bold}${hostname}${text_reset} found, make sure the directory ${text_bold}${dotfiles}/hosts/${hostname}${text_reset} exists"
fi
# Get dotfiles for current host
mapfile -t files < <(find -L "${dotfiles}/hosts/${hostname}" -type f -printf '%P\n')
if [ "$unlink" == true ]; then
log "Unlinking ${text_bold}${#files[@]}${text_reset} files..\n"
else
log "Linking ${text_bold}${#files[@]}${text_reset} files..\n"
fi
for file in "${files[@]}"; do
src="${dotfiles}/hosts/${hostname}/${file}"
trgt="${HOME}/${file}"
# Unlink files
if [ "$unlink" == true ]; then
if [ -L "$trgt" ] && [ "$(readlink "$trgt")" == "$src" ]; then
rm "$trgt"
log "Unlinked ${text_bold}${trgt}${text_reset}"
# Remove target directory if empty
if ! [ "$(ls -A "$(dirname "$trgt")")" ]; then
rmdir "$(dirname "$trgt")"
log "Removed empty directory ${text_bold}$(dirname "$trgt")${text_reset}"
fi
fi
# Link files
else
# Check if target is a link
if [ -L "$trgt" ]; then
if [ "$(readlink "$trgt")" != "$src" ]; then
warning "${text_bold}${trgt}${text_reset} is a link but doesn't point to this repository, it will not be linked"
continue
fi
# Check if target is a file or directory
elif [ -f "$trgt" ]; then
warning "${text_bold}${trgt}${text_reset} exists and will not be linked"
continue
# Create link
else
# Create target directory if not existent
mkdir -p "$(dirname "$trgt")"
# Link file
ln -s "$src" "$trgt"
log "Linked ${text_bold}${src}${text_reset} to ${text_bold}${trgt}${text_reset}"
fi
fi
done
log "\ndone"