kitowall 7.5.0 → 7.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -6
- package/dist/cli.js +55 -4
- package/dist/core/setup.js +416 -0
- package/package.json +3 -1
- package/scripts/bootstrap-host.sh +552 -0
- package/scripts/bootstrap-system.sh +187 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Host bootstrap for AppImage/non-Flatpak installations.
|
|
5
|
+
# Installs system dependencies plus kitowall/kitsune/kitsune-rendercore binaries.
|
|
6
|
+
|
|
7
|
+
KITSUNE_REPO="${KITSUNE_REPO:-https://github.com/KitotsuMolina/Kitsune.git}"
|
|
8
|
+
KITSUNE_RENDERCORE_REPO="${KITSUNE_RENDERCORE_REPO:-https://github.com/KitotsuMolina/Kitsune-RenderCore.git}"
|
|
9
|
+
KITSUNE_TAG="${KITSUNE_TAG:-}"
|
|
10
|
+
KITSUNE_RENDERCORE_TAG="${KITSUNE_RENDERCORE_TAG:-}"
|
|
11
|
+
KITOWALL_BOOTSTRAP_MODE="${KITOWALL_BOOTSTRAP_MODE:-full}"
|
|
12
|
+
KITOWALL_SKIP_SYSTEM_DEPS="${KITOWALL_SKIP_SYSTEM_DEPS:-0}"
|
|
13
|
+
|
|
14
|
+
BOOTSTRAP_KITSUNE_VERSION=""
|
|
15
|
+
BOOTSTRAP_RENDERCORE_VERSION=""
|
|
16
|
+
|
|
17
|
+
need_cmd() {
|
|
18
|
+
command -v "$1" >/dev/null 2>&1
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
prepend_user_path() {
|
|
22
|
+
local home_dir="${HOME:?HOME is required}"
|
|
23
|
+
export PATH="$home_dir/.local/bin:$home_dir/.cargo/bin:$PATH"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
run_sudo() {
|
|
27
|
+
if need_cmd sudo; then
|
|
28
|
+
sudo "$@"
|
|
29
|
+
else
|
|
30
|
+
"$@"
|
|
31
|
+
fi
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
wait_pacman_lock() {
|
|
35
|
+
local lock_file="/var/lib/pacman/db.lck"
|
|
36
|
+
local tries=0
|
|
37
|
+
local max_tries=40
|
|
38
|
+
|
|
39
|
+
while [[ -e "$lock_file" ]]; do
|
|
40
|
+
# If a package manager is still running, just wait.
|
|
41
|
+
if pgrep -x pacman >/dev/null 2>&1 || \
|
|
42
|
+
pgrep -x yay >/dev/null 2>&1 || \
|
|
43
|
+
pgrep -x paru >/dev/null 2>&1 || \
|
|
44
|
+
pgrep -x makepkg >/dev/null 2>&1; then
|
|
45
|
+
tries=$((tries + 1))
|
|
46
|
+
if ((tries > max_tries)); then
|
|
47
|
+
echo "[bootstrap] pacman lock is busy for too long: $lock_file" >&2
|
|
48
|
+
return 1
|
|
49
|
+
fi
|
|
50
|
+
echo "[bootstrap] waiting for pacman lock (${tries}/${max_tries})..."
|
|
51
|
+
sleep 3
|
|
52
|
+
continue
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# No package process alive: stale lock, safe to remove.
|
|
56
|
+
echo "[bootstrap] removing stale pacman lock: $lock_file"
|
|
57
|
+
run_sudo rm -f "$lock_file"
|
|
58
|
+
break
|
|
59
|
+
done
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ensure_user_bin_dirs() {
|
|
63
|
+
local home_dir
|
|
64
|
+
home_dir="${HOME:?HOME is required}"
|
|
65
|
+
mkdir -p "$home_dir/.local/bin" "$home_dir/.cargo/bin"
|
|
66
|
+
prepend_user_path
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
install_arch_deps() {
|
|
70
|
+
local repo_pkgs=(
|
|
71
|
+
nodejs npm
|
|
72
|
+
hyprland
|
|
73
|
+
swww
|
|
74
|
+
cava
|
|
75
|
+
pkgconf
|
|
76
|
+
gtk4
|
|
77
|
+
gtk4-layer-shell
|
|
78
|
+
jq
|
|
79
|
+
git
|
|
80
|
+
base-devel
|
|
81
|
+
)
|
|
82
|
+
# Avoid rust/rustup conflicts on Arch.
|
|
83
|
+
if need_cmd rustup; then
|
|
84
|
+
repo_pkgs+=(rustup)
|
|
85
|
+
elif need_cmd rustc && need_cmd cargo; then
|
|
86
|
+
:
|
|
87
|
+
else
|
|
88
|
+
repo_pkgs+=(rustup)
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
echo "[bootstrap] installing Arch repo packages: ${repo_pkgs[*]}"
|
|
92
|
+
wait_pacman_lock
|
|
93
|
+
run_sudo pacman -S --needed --noconfirm "${repo_pkgs[@]}"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
install_ubuntu_deps() {
|
|
97
|
+
local pkgs=(
|
|
98
|
+
nodejs npm
|
|
99
|
+
rustc cargo
|
|
100
|
+
pkg-config
|
|
101
|
+
libgtk-4-dev
|
|
102
|
+
jq curl git
|
|
103
|
+
cava
|
|
104
|
+
)
|
|
105
|
+
echo "[bootstrap] installing Debian/Ubuntu packages: ${pkgs[*]}"
|
|
106
|
+
run_sudo apt-get update
|
|
107
|
+
run_sudo apt-get install -y "${pkgs[@]}"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
install_system_deps() {
|
|
111
|
+
if need_cmd pacman; then
|
|
112
|
+
install_arch_deps
|
|
113
|
+
return
|
|
114
|
+
fi
|
|
115
|
+
if need_cmd apt-get; then
|
|
116
|
+
install_ubuntu_deps
|
|
117
|
+
return
|
|
118
|
+
fi
|
|
119
|
+
echo "[bootstrap] unsupported distro package manager. Install manually: nodejs npm rust cargo pkg-config gtk4 gtk4-layer-shell swww hyprland cava" >&2
|
|
120
|
+
exit 1
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
install_kitowall_cli() {
|
|
124
|
+
if ! need_cmd npm; then
|
|
125
|
+
echo "[bootstrap] npm is not available after dependency install" >&2
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
local home_dir
|
|
129
|
+
home_dir="${HOME:?HOME is required}"
|
|
130
|
+
echo "[bootstrap] installing/updating kitowall CLI in user prefix ($home_dir/.local)"
|
|
131
|
+
npm i -g --prefix "$home_dir/.local" kitowall
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
install_github_release_bin() {
|
|
135
|
+
local repo="$1" # owner/name
|
|
136
|
+
local asset_name="$2" # exact asset name
|
|
137
|
+
local out_bin="$3" # absolute output path
|
|
138
|
+
|
|
139
|
+
if ! need_cmd curl; then
|
|
140
|
+
echo "[bootstrap] missing curl for GitHub release install" >&2
|
|
141
|
+
return 1
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
local asset_url="https://github.com/${repo}/releases/latest/download/${asset_name}"
|
|
145
|
+
local release_tag=""
|
|
146
|
+
local out_dir tmp_bin
|
|
147
|
+
out_dir="$(dirname "$out_bin")"
|
|
148
|
+
mkdir -p "$out_dir"
|
|
149
|
+
tmp_bin="$(mktemp "${out_dir}/.${asset_name}.XXXXXX.tmp")"
|
|
150
|
+
|
|
151
|
+
echo "[bootstrap] downloading ${repo} asset: ${asset_name}"
|
|
152
|
+
if ! curl -fL \
|
|
153
|
+
--retry 3 \
|
|
154
|
+
--retry-delay 2 \
|
|
155
|
+
-H "User-Agent: Kitowall-Bootstrap" \
|
|
156
|
+
-H "Accept: application/octet-stream" \
|
|
157
|
+
"$asset_url" -o "$tmp_bin"; then
|
|
158
|
+
rm -f "$tmp_bin"
|
|
159
|
+
release_tag="$(latest_release_tag "$repo" || true)"
|
|
160
|
+
if [[ -n "${release_tag:-}" ]]; then
|
|
161
|
+
asset_url="https://github.com/${repo}/releases/download/${release_tag}/${asset_name}"
|
|
162
|
+
echo "[bootstrap] retrying ${repo} asset with explicit tag: ${release_tag}"
|
|
163
|
+
tmp_bin="$(mktemp "${out_dir}/.${asset_name}.XXXXXX.tmp")"
|
|
164
|
+
if ! curl -fL \
|
|
165
|
+
--retry 3 \
|
|
166
|
+
--retry-delay 2 \
|
|
167
|
+
-H "User-Agent: Kitowall-Bootstrap" \
|
|
168
|
+
-H "Accept: application/octet-stream" \
|
|
169
|
+
"$asset_url" -o "$tmp_bin"; then
|
|
170
|
+
rm -f "$tmp_bin"
|
|
171
|
+
return 1
|
|
172
|
+
fi
|
|
173
|
+
else
|
|
174
|
+
return 1
|
|
175
|
+
fi
|
|
176
|
+
fi
|
|
177
|
+
chmod 755 "$tmp_bin"
|
|
178
|
+
mv -f "$tmp_bin" "$out_bin"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
latest_release_tag() {
|
|
182
|
+
local repo="$1"
|
|
183
|
+
|
|
184
|
+
if ! need_cmd curl || ! need_cmd jq; then
|
|
185
|
+
return 1
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
curl -fsSL "https://api.github.com/repos/${repo}/releases/latest" | jq -r '.tag_name // empty'
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
write_kitsune_wrapper() {
|
|
192
|
+
local home_dir="${HOME:?HOME is required}"
|
|
193
|
+
local share_dir="$home_dir/.local/share/kitsune"
|
|
194
|
+
local config_dir="$home_dir/.config/kitsune"
|
|
195
|
+
local state_dir="$home_dir/.local/state/kitsune"
|
|
196
|
+
|
|
197
|
+
mkdir -p "$home_dir/.local/bin" "$config_dir" "$state_dir/run"
|
|
198
|
+
rm -f "$home_dir/.local/bin/kitsune"
|
|
199
|
+
cat > "$home_dir/.local/bin/kitsune" <<EOF
|
|
200
|
+
#!/usr/bin/env bash
|
|
201
|
+
set -euo pipefail
|
|
202
|
+
export KITSUNE_HOME="$share_dir"
|
|
203
|
+
export KITSUNE_BIN_DIR="$share_dir/bin"
|
|
204
|
+
export KITSUNE_CFG="$config_dir/base.conf"
|
|
205
|
+
export KITSUNE_CAVA_CFG="$config_dir/cava.conf"
|
|
206
|
+
export KITSUNE_RUN_PREFIX="$state_dir/run"
|
|
207
|
+
mkdir -p "\$KITSUNE_RUN_PREFIX"
|
|
208
|
+
exec "$share_dir/scripts/kitsune.sh" "\$@"
|
|
209
|
+
EOF
|
|
210
|
+
chmod 755 "$home_dir/.local/bin/kitsune"
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
is_kitsune_bundle_corrupted() {
|
|
214
|
+
local home_dir="${HOME:?HOME is required}"
|
|
215
|
+
local script_path="$home_dir/.local/share/kitsune/scripts/kitsune.sh"
|
|
216
|
+
|
|
217
|
+
[[ ! -f "$script_path" ]] && return 0
|
|
218
|
+
grep -Fq 'exec "/home/' "$script_path" && grep -Fq '/scripts/kitsune.sh" "$@"' "$script_path"
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
is_kitsune_binary_corrupted() {
|
|
222
|
+
local home_dir="${HOME:?HOME is required}"
|
|
223
|
+
local bin_path="$home_dir/.local/share/kitsune/bin/kitsune"
|
|
224
|
+
|
|
225
|
+
[[ ! -f "$bin_path" ]] && return 0
|
|
226
|
+
file "$bin_path" 2>/dev/null | grep -Fq 'ELF' || return 0
|
|
227
|
+
return 1
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
repair_kitsune_host_layout() {
|
|
231
|
+
local home_dir="${HOME:?HOME is required}"
|
|
232
|
+
local share_dir="$home_dir/.local/share/kitsune"
|
|
233
|
+
local config_dir="$home_dir/.config/kitsune"
|
|
234
|
+
local state_dir="$home_dir/.local/state/kitsune"
|
|
235
|
+
|
|
236
|
+
if [[ ! -d "$share_dir/scripts" || ! -d "$share_dir/bin" ]]; then
|
|
237
|
+
echo "[bootstrap] kitsune share layout missing in $share_dir; run full bootstrap first" >&2
|
|
238
|
+
return 1
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
if is_kitsune_binary_corrupted; then
|
|
242
|
+
echo "[bootstrap] kitsune binary is corrupted; restoring binaries from latest release"
|
|
243
|
+
install_kitsune_bins
|
|
244
|
+
return 0
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
if is_kitsune_bundle_corrupted; then
|
|
248
|
+
echo "[bootstrap] kitsune bundle is corrupted; restoring bundle from latest release"
|
|
249
|
+
install_kitsune_bundle
|
|
250
|
+
return 0
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
mkdir -p "$config_dir" "$state_dir/run"
|
|
254
|
+
if [[ -f "$share_dir/config/base.conf" && ! -f "$config_dir/base.conf" ]]; then
|
|
255
|
+
cp "$share_dir/config/base.conf" "$config_dir/base.conf"
|
|
256
|
+
fi
|
|
257
|
+
if [[ -f "$share_dir/config/cava.conf" && ! -f "$config_dir/cava.conf" ]]; then
|
|
258
|
+
cp "$share_dir/config/cava.conf" "$config_dir/cava.conf"
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
write_kitsune_wrapper
|
|
262
|
+
echo "[bootstrap] repaired kitsune host layout"
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
install_kitsune_bundle() {
|
|
266
|
+
local home_dir="${HOME:?HOME is required}"
|
|
267
|
+
local share_dir="$home_dir/.local/share/kitsune"
|
|
268
|
+
local config_dir="$home_dir/.config/kitsune"
|
|
269
|
+
local state_dir="$home_dir/.local/state/kitsune"
|
|
270
|
+
local tmp_dir
|
|
271
|
+
tmp_dir="$(mktemp -d)"
|
|
272
|
+
|
|
273
|
+
if ! need_cmd curl || ! need_cmd jq || ! need_cmd tar; then
|
|
274
|
+
echo "[bootstrap] missing curl/jq/tar for kitsune bundle install" >&2
|
|
275
|
+
rm -rf "$tmp_dir"
|
|
276
|
+
return 1
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
local api_url="https://api.github.com/repos/KitotsuMolina/Kitsune/releases/latest"
|
|
280
|
+
local tar_url
|
|
281
|
+
tar_url="$(curl -fsSL "$api_url" | jq -r '.tarball_url // empty')"
|
|
282
|
+
if [[ -z "${tar_url:-}" || "$tar_url" == "null" ]]; then
|
|
283
|
+
echo "[bootstrap] kitsune release tarball URL not found" >&2
|
|
284
|
+
rm -rf "$tmp_dir"
|
|
285
|
+
return 1
|
|
286
|
+
fi
|
|
287
|
+
|
|
288
|
+
echo "[bootstrap] downloading kitsune bundle sources"
|
|
289
|
+
curl -fL --retry 3 --retry-delay 2 "$tar_url" -o "$tmp_dir/kitsune.tar.gz"
|
|
290
|
+
tar -xzf "$tmp_dir/kitsune.tar.gz" -C "$tmp_dir"
|
|
291
|
+
local src_dir
|
|
292
|
+
src_dir="$(find "$tmp_dir" -mindepth 1 -maxdepth 1 -type d | head -n1)"
|
|
293
|
+
if [[ -z "${src_dir:-}" || ! -d "$src_dir/scripts" || ! -d "$src_dir/config" ]]; then
|
|
294
|
+
echo "[bootstrap] invalid kitsune source layout in tarball" >&2
|
|
295
|
+
rm -rf "$tmp_dir"
|
|
296
|
+
return 1
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
mkdir -p "$share_dir" "$config_dir" "$state_dir"
|
|
300
|
+
rm -rf "$share_dir/scripts" "$share_dir/config" "$share_dir/completions"
|
|
301
|
+
cp -a "$src_dir/scripts" "$share_dir/"
|
|
302
|
+
cp -a "$src_dir/config" "$share_dir/"
|
|
303
|
+
[[ -d "$src_dir/completions" ]] && cp -a "$src_dir/completions" "$share_dir/" || true
|
|
304
|
+
mkdir -p "$share_dir/bin"
|
|
305
|
+
|
|
306
|
+
if [[ ! -f "$config_dir/base.conf" ]]; then
|
|
307
|
+
cp "$share_dir/config/base.conf" "$config_dir/base.conf"
|
|
308
|
+
fi
|
|
309
|
+
if [[ ! -f "$config_dir/cava.conf" ]]; then
|
|
310
|
+
cp "$share_dir/config/cava.conf" "$config_dir/cava.conf"
|
|
311
|
+
fi
|
|
312
|
+
|
|
313
|
+
# Ensure scripts point to prebuilt binaries instead of local cargo build paths.
|
|
314
|
+
sed -i \
|
|
315
|
+
-e '/^echo "\[i\] Building Rust renderer\.\.\."$/d' \
|
|
316
|
+
-e '/^cargo build --release --locked --bins$/d' \
|
|
317
|
+
-e '/^cargo build --release --bins$/d' \
|
|
318
|
+
-e '/^echo "\[i\] Building GTK overlay frontend\.\.\."$/d' \
|
|
319
|
+
-e '/^cargo build --release --bin kitsune-overlay$/d' \
|
|
320
|
+
-e 's|\./target/release/kitsune-overlay|"${KITSUNE_BIN_DIR:-./bin}"/kitsune-overlay|g' \
|
|
321
|
+
-e 's|\./target/release/kitsune|"${KITSUNE_BIN_DIR:-./bin}"/kitsune|g' \
|
|
322
|
+
-e 's|"${KITSUNE_BIN_DIR:-./bin}"/kitsune --config|"${KITSUNE_BIN_DIR:-./bin}"/kitsune run --config|g' \
|
|
323
|
+
"$share_dir/scripts/start.sh" \
|
|
324
|
+
"$share_dir/scripts/kitsune.sh"
|
|
325
|
+
sed -i -e '/^cargo build --release$/d' "$share_dir/scripts/install.sh" || true
|
|
326
|
+
|
|
327
|
+
write_kitsune_wrapper
|
|
328
|
+
|
|
329
|
+
rm -rf "$tmp_dir"
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
cargo_install_git_bin() {
|
|
333
|
+
local repo="$1"
|
|
334
|
+
local bin="$2"
|
|
335
|
+
local extra_args="$3"
|
|
336
|
+
local tag="${4:-}"
|
|
337
|
+
|
|
338
|
+
local args=(install --git "$repo" --locked --force "$bin")
|
|
339
|
+
if [[ -n "$tag" ]]; then
|
|
340
|
+
args+=(--tag "$tag")
|
|
341
|
+
fi
|
|
342
|
+
if [[ -n "$extra_args" ]]; then
|
|
343
|
+
# shellcheck disable=SC2206
|
|
344
|
+
local split_extra=($extra_args)
|
|
345
|
+
args+=("${split_extra[@]}")
|
|
346
|
+
fi
|
|
347
|
+
|
|
348
|
+
echo "[bootstrap] cargo ${args[*]}"
|
|
349
|
+
cargo "${args[@]}"
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
install_kitsune_bins() {
|
|
353
|
+
local home_dir="${HOME:?HOME is required}"
|
|
354
|
+
local bin_dir="$home_dir/.local/bin"
|
|
355
|
+
local share_bin_dir="$home_dir/.local/share/kitsune/bin"
|
|
356
|
+
local release_ok=0
|
|
357
|
+
mkdir -p "$share_bin_dir"
|
|
358
|
+
|
|
359
|
+
# Prefer prebuilt binaries from GitHub Releases to avoid local toolchain/submodule issues.
|
|
360
|
+
if install_github_release_bin "KitotsuMolina/Kitsune" "kitsune-linux-x86_64" "$share_bin_dir/kitsune" && \
|
|
361
|
+
install_github_release_bin "KitotsuMolina/Kitsune" "kitsune-overlay-linux-x86_64" "$share_bin_dir/kitsune-overlay" && \
|
|
362
|
+
install_github_release_bin "KitotsuMolina/Kitsune" "kitsune-color-resolve-linux-x86_64" "$share_bin_dir/kitsune-color-resolve" && \
|
|
363
|
+
install_github_release_bin "KitotsuMolina/Kitsune-RenderCore" "kitsune-rendercore-linux-x86_64" "$bin_dir/kitsune-rendercore"; then
|
|
364
|
+
ln -sf "$share_bin_dir/kitsune-overlay" "$bin_dir/kitsune-overlay"
|
|
365
|
+
ln -sf "$share_bin_dir/kitsune-color-resolve" "$bin_dir/kitsune-color-resolve"
|
|
366
|
+
BOOTSTRAP_KITSUNE_VERSION="$(latest_release_tag "KitotsuMolina/Kitsune" | sed 's/^v//')"
|
|
367
|
+
BOOTSTRAP_RENDERCORE_VERSION="$(latest_release_tag "KitotsuMolina/Kitsune-RenderCore" | sed 's/^v//')"
|
|
368
|
+
release_ok=1
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
if [[ "$release_ok" -eq 1 ]]; then
|
|
372
|
+
install_kitsune_bundle || echo "[bootstrap] warning: failed to install kitsune script bundle; falling back to raw binary command" >&2
|
|
373
|
+
return
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
echo "[bootstrap] warning: release binary install failed, falling back to cargo install" >&2
|
|
377
|
+
if ! need_cmd cargo; then
|
|
378
|
+
echo "[bootstrap] cargo is not available after dependency install" >&2
|
|
379
|
+
exit 1
|
|
380
|
+
fi
|
|
381
|
+
cargo_install_git_bin "$KITSUNE_REPO" kitsune "" "$KITSUNE_TAG"
|
|
382
|
+
cargo_install_git_bin "$KITSUNE_RENDERCORE_REPO" kitsune-rendercore "--features wayland-layer" "$KITSUNE_RENDERCORE_TAG"
|
|
383
|
+
BOOTSTRAP_KITSUNE_VERSION="${KITSUNE_TAG#v}"
|
|
384
|
+
BOOTSTRAP_RENDERCORE_VERSION="${KITSUNE_RENDERCORE_TAG#v}"
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
ensure_rendercore_service() {
|
|
388
|
+
if ! need_cmd kitsune-rendercore; then
|
|
389
|
+
echo "[bootstrap] warning: kitsune-rendercore binary not found; skipping service install" >&2
|
|
390
|
+
return
|
|
391
|
+
fi
|
|
392
|
+
|
|
393
|
+
local home_dir="${HOME:?HOME is required}"
|
|
394
|
+
local user_systemd_dir="$home_dir/.config/systemd/user"
|
|
395
|
+
local app_config_dir="$home_dir/.config/kitsune-rendercore"
|
|
396
|
+
local env_dst="$app_config_dir/env"
|
|
397
|
+
local map_dst="$app_config_dir/video-map.conf"
|
|
398
|
+
local bin_path
|
|
399
|
+
bin_path="$(command -v kitsune-rendercore || true)"
|
|
400
|
+
if [[ -z "$bin_path" ]]; then
|
|
401
|
+
echo "[bootstrap] warning: kitsune-rendercore binary path not found; skipping service install" >&2
|
|
402
|
+
return
|
|
403
|
+
fi
|
|
404
|
+
|
|
405
|
+
mkdir -p "$user_systemd_dir" "$app_config_dir"
|
|
406
|
+
if [[ ! -f "$env_dst" ]]; then
|
|
407
|
+
cat > "$env_dst" <<EOF
|
|
408
|
+
# Kitsune RenderCore user env
|
|
409
|
+
KRC_VIDEO_MAP_FILE=$map_dst
|
|
410
|
+
KRC_VIDEO_FPS=30
|
|
411
|
+
KRC_VIDEO_SPEED=1.0
|
|
412
|
+
KRC_QUALITY=high
|
|
413
|
+
KRC_PAUSE_ON_STEAM_GAME=true
|
|
414
|
+
KRC_STEAM_POLL_MS=1000
|
|
415
|
+
EOF
|
|
416
|
+
fi
|
|
417
|
+
if [[ ! -f "$map_dst" ]]; then
|
|
418
|
+
: > "$map_dst"
|
|
419
|
+
fi
|
|
420
|
+
|
|
421
|
+
cat > "$user_systemd_dir/kitsune-rendercore.service" <<EOF
|
|
422
|
+
[Unit]
|
|
423
|
+
Description=Kitsune RenderCore Live Wallpaper
|
|
424
|
+
After=graphical-session.target
|
|
425
|
+
Wants=graphical-session.target
|
|
426
|
+
|
|
427
|
+
[Service]
|
|
428
|
+
Type=simple
|
|
429
|
+
Environment=PATH=$home_dir/.local/bin:$home_dir/.cargo/bin:/usr/local/bin:/usr/bin:/bin
|
|
430
|
+
EnvironmentFile=-$env_dst
|
|
431
|
+
ExecStart=$bin_path
|
|
432
|
+
Restart=on-failure
|
|
433
|
+
RestartSec=1
|
|
434
|
+
|
|
435
|
+
[Install]
|
|
436
|
+
WantedBy=default.target
|
|
437
|
+
EOF
|
|
438
|
+
|
|
439
|
+
systemctl --user daemon-reload || true
|
|
440
|
+
systemctl --user enable kitsune-rendercore.service || true
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
verify_bins() {
|
|
444
|
+
local required_bins=()
|
|
445
|
+
if [[ "$KITOWALL_BOOTSTRAP_MODE" == "kitsune-only" || "$KITOWALL_BOOTSTRAP_MODE" == "kitsune-repair" ]]; then
|
|
446
|
+
required_bins=(kitsune kitsune-rendercore)
|
|
447
|
+
elif [[ "$KITOWALL_BOOTSTRAP_MODE" == "kitowall-only" ]]; then
|
|
448
|
+
required_bins=(kitowall)
|
|
449
|
+
else
|
|
450
|
+
required_bins=(kitowall kitsune kitsune-rendercore swww swww-daemon cava)
|
|
451
|
+
fi
|
|
452
|
+
local missing=()
|
|
453
|
+
for b in "${required_bins[@]}"; do
|
|
454
|
+
if ! need_cmd "$b"; then
|
|
455
|
+
missing+=("$b")
|
|
456
|
+
fi
|
|
457
|
+
done
|
|
458
|
+
|
|
459
|
+
if ((${#missing[@]} > 0)); then
|
|
460
|
+
echo "[bootstrap] missing binaries after bootstrap: ${missing[*]}" >&2
|
|
461
|
+
|
|
462
|
+
local needs_kitsune_recovery=0
|
|
463
|
+
for b in "${missing[@]}"; do
|
|
464
|
+
if [[ "$b" == "kitsune" || "$b" == "kitsune-rendercore" ]]; then
|
|
465
|
+
needs_kitsune_recovery=1
|
|
466
|
+
break
|
|
467
|
+
fi
|
|
468
|
+
done
|
|
469
|
+
|
|
470
|
+
if [[ "$needs_kitsune_recovery" -eq 1 ]]; then
|
|
471
|
+
echo "[bootstrap] attempting release-based recovery for Kitsune binaries" >&2
|
|
472
|
+
install_kitsune_bins
|
|
473
|
+
missing=()
|
|
474
|
+
for b in "${required_bins[@]}"; do
|
|
475
|
+
if ! need_cmd "$b"; then
|
|
476
|
+
missing+=("$b")
|
|
477
|
+
fi
|
|
478
|
+
done
|
|
479
|
+
fi
|
|
480
|
+
|
|
481
|
+
if ((${#missing[@]} > 0)); then
|
|
482
|
+
echo "[bootstrap] missing binaries after recovery: ${missing[*]}" >&2
|
|
483
|
+
exit 2
|
|
484
|
+
fi
|
|
485
|
+
fi
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
write_bootstrap_versions() {
|
|
489
|
+
local home_dir="${HOME:?HOME is required}"
|
|
490
|
+
local state_dir="$home_dir/.local/share/kitowall"
|
|
491
|
+
local state_file="$state_dir/bootstrap-versions.json"
|
|
492
|
+
|
|
493
|
+
mkdir -p "$state_dir"
|
|
494
|
+
cat > "$state_file" <<EOF
|
|
495
|
+
{
|
|
496
|
+
"kitsune": {
|
|
497
|
+
"version": "${BOOTSTRAP_KITSUNE_VERSION}",
|
|
498
|
+
"source": "${KITOWALL_BOOTSTRAP_MODE}"
|
|
499
|
+
},
|
|
500
|
+
"kitsune-rendercore": {
|
|
501
|
+
"version": "${BOOTSTRAP_RENDERCORE_VERSION}",
|
|
502
|
+
"source": "${KITOWALL_BOOTSTRAP_MODE}"
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
EOF
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
main() {
|
|
509
|
+
# Some launchers provide a stale/non-existent CWD; recover to HOME.
|
|
510
|
+
cd "${HOME:?HOME is required}" || true
|
|
511
|
+
# Clean host Python env that can break AUR build tools (meson/python).
|
|
512
|
+
unset PYTHONHOME || true
|
|
513
|
+
unset PYTHONPATH || true
|
|
514
|
+
|
|
515
|
+
ensure_user_bin_dirs
|
|
516
|
+
if [[ "$KITOWALL_BOOTSTRAP_MODE" == "kitsune-repair" ]]; then
|
|
517
|
+
repair_kitsune_host_layout
|
|
518
|
+
verify_bins
|
|
519
|
+
echo "[ok] kitsune host repair complete"
|
|
520
|
+
exit 0
|
|
521
|
+
fi
|
|
522
|
+
if [[ "$KITOWALL_BOOTSTRAP_MODE" == "kitowall-only" ]]; then
|
|
523
|
+
if [[ "$KITOWALL_SKIP_SYSTEM_DEPS" != "1" ]]; then
|
|
524
|
+
install_system_deps
|
|
525
|
+
fi
|
|
526
|
+
install_kitowall_cli
|
|
527
|
+
verify_bins
|
|
528
|
+
echo "[ok] kitowall bootstrap complete"
|
|
529
|
+
echo "[paths] HOME=$HOME"
|
|
530
|
+
echo "[paths] kitowall=$(command -v kitowall || echo '<missing>')"
|
|
531
|
+
echo "[info] bootstrap finished; manual init is only needed on a fresh host without config"
|
|
532
|
+
exit 0
|
|
533
|
+
fi
|
|
534
|
+
if [[ "$KITOWALL_BOOTSTRAP_MODE" != "kitsune-only" && "$KITOWALL_SKIP_SYSTEM_DEPS" != "1" ]]; then
|
|
535
|
+
install_system_deps
|
|
536
|
+
install_kitowall_cli
|
|
537
|
+
elif [[ "$KITOWALL_BOOTSTRAP_MODE" != "kitsune-only" ]]; then
|
|
538
|
+
install_kitowall_cli
|
|
539
|
+
fi
|
|
540
|
+
install_kitsune_bins
|
|
541
|
+
ensure_rendercore_service
|
|
542
|
+
write_bootstrap_versions
|
|
543
|
+
verify_bins
|
|
544
|
+
echo "[ok] host bootstrap complete"
|
|
545
|
+
echo "[paths] HOME=$HOME"
|
|
546
|
+
echo "[paths] kitowall=$(command -v kitowall || echo '<missing>')"
|
|
547
|
+
echo "[paths] kitsune=$(command -v kitsune || echo '<missing>')"
|
|
548
|
+
echo "[paths] kitsune-rendercore=$(command -v kitsune-rendercore || echo '<missing>')"
|
|
549
|
+
echo "[info] bootstrap finished; manual init is only needed on a fresh host without config"
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
main "$@"
|