-
Notifications
You must be signed in to change notification settings - Fork 0
/
caches-manager
executable file
·184 lines (148 loc) · 3.69 KB
/
caches-manager
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
#!/bin/bash
APP_NAME="caches-manager"
set -euo pipefail
shopt -s nullglob dotglob
# $1: target directory
backup() {
[ -e "$1" ] || return 0
echo -n "target exists, backing up... "
mv -T --backup=numbered "$1" "$1.bak"
}
# $1: target directory
is_not_empty() {
for _ in "$1/"*; do
return 0
done
return 1
}
# $1: target directory
make_mount() {
if ((UID != 0)); then
echo "can not mount without root privileges, skip."
return 13
fi
if [ ! -d "$1" ]; then
echo "the target is not a directory, skip."
return 1
fi
is_not_empty "$1" &&
echo -n "(warning: the directory is not empty, existing content will be overlayed) "
mount -t tmpfs -o "rw,$(stat -c 'mode=%a,uid=%u,gid=%g' "$1")" tmpfs "$1"
}
# $1: virtual directory to link
# $2: target directory
make_link() {
if [ -L "$2" ]; then
[ "$(readlink "$2")" == "$1" ] && return 0
else
backup "$2"
fi
ln -sfT "$1" "$2"
}
# $1: virtual directory to create
# $2: target directory
# $3: creation flag
create_cache() {
local dir
local parent
dir="$(realpath -s "$2")"
parent="$(dirname "${dir}")"
if [ "$3" == "b" ]; then
echo -n "Mounting '${dir}'... "
else
echo -n "Linking '${dir}'... "
mkdir -p "$1"
fi
if [ ! -d "${parent}" ]; then
echo "parent directory does not exist, skip."
return 0
fi
if mountpoint -q "${dir}"; then
echo "mount point found, skip."
return 0
fi
if [ "$3" == "b" ]; then
make_mount "${dir}" || return 0
else
if [ ! -w "${parent}" ]; then
echo "no write access to parent directory, skip."
return 0
fi
make_link "$1" "${dir}" || return 0
fi
echo "done."
}
declare -a TARGETS
# $1: virtual directory where caches will be created
# $2: prefix for paths resolving
create_caches() {
local flag
local path
for t in "${TARGETS[@]}"; do
[ "${t:0:1}" == "#" ] && continue
flag="$(expr "${t}" : '\(.*\):')" || true
path="${t#*:}"
create_cache "$1/${path}" "$2/${path}" "${flag}"
done
}
# $1: config file
read_config() {
while read -r line || [ -n "${line}" ]; do
[ "${line}" ] && TARGETS+=("${line}")
done < "$1"
}
# $1: configs directory
read_configs_from() {
[ -d "$1" ] || return 0
for f in "$1/"*.conf; do
read_config "${f}"
done
}
create_system_caches() {
if ((UID != 0)); then
echo "System job requires root privileges."
return 13
fi
local dir="/dev/shm"
if [ ! -d "${dir}" ]; then
echo "System tmpfs directory '${dir}' not found."
return 2
fi
echo "Processing system targets..."
TARGETS=()
read_configs_from "/etc/${APP_NAME}/system"
create_caches "${dir}/tmp" ""
}
create_user_caches() {
local dir="${XDG_RUNTIME_DIR:-"/run/user/${UID}"}"
if [ ! -d "${dir}" ]; then
echo "User tmpfs directory '${dir}' not found."
return 2
fi
echo "Processing user targets..."
TARGETS=()
read_configs_from "/etc/${APP_NAME}/user"
read_configs_from "${XDG_CONFIG_HOME:-"${HOME}/.config"}/${APP_NAME}"
create_caches "${dir}/tmp" "${HOME}"
}
if (($# == 0)); then
echo "No arguments provided."
echo "Notice: running this script manually is not recommended."
echo " --system run system job"
echo " --user run user job"
exit
fi
declare -A ARGS=()
for arg in "$@"; do
ARGS["${arg}"]=1
done
# $1: argument to check
has_arg() {
[ "${ARGS["$1"]:-}" ]
}
if has_arg '--system'; then
create_system_caches
fi
if has_arg '--user'; then
create_user_caches
fi