fix(sysupdate): make hypr config sync atomic
The hypr/ sync removed each live item with `rm -rf` before `cp`. For
hyprland.lua this opened a window where the file was absent; if Hyprland's
live config watcher reloaded during it, it errored ("cannot open
hyprland.lua") and wrote out its fallback hyprland.conf stub, which then
leaked into the repo.
Stage each item into a temp dir on the same filesystem and `mv` it into
place — for files this is an atomic rename(2), so the watcher never sees
hyprland.lua missing. Directories are cleared first (mv can't replace a
non-empty dir), but those aren't watched config files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
main
parent
d35d6d17d6
commit
dc3ffb68b7
29
sysupdate.sh
29
sysupdate.sh
|
|
@ -616,15 +616,30 @@ sync_configs() {
|
||||||
[[ "$skip" == true ]] && continue
|
[[ "$skip" == true ]] && continue
|
||||||
|
|
||||||
if [[ "$name" == "hypr" ]]; then
|
if [[ "$name" == "hypr" ]]; then
|
||||||
# Copy hypr/ contents but preserve ~/.config/hypr/usr/
|
# Copy hypr/ contents but preserve ~/.config/hypr/usr/.
|
||||||
|
# Stage each item into a temp dir on the same filesystem, then mv it
|
||||||
|
# into place — for files this is an atomic rename(2), so Hyprland's
|
||||||
|
# live config watcher never sees hyprland.lua momentarily missing
|
||||||
|
# (which otherwise makes it emit its fallback hyprland.conf stub).
|
||||||
mkdir -p "$target/hypr"
|
mkdir -p "$target/hypr"
|
||||||
local hypr_ok=true
|
local hypr_ok=true
|
||||||
while IFS= read -r -d '' hitem; do
|
local stage; stage="$(mktemp -d "${target}/hypr/.sync.XXXXXX")" || hypr_ok=false
|
||||||
local hname; hname="$(basename "$hitem")"
|
if $hypr_ok; then
|
||||||
[[ "$hname" == "usr" ]] && continue
|
while IFS= read -r -d '' hitem; do
|
||||||
rm -rf "${target}/hypr/${hname}" && cp -r "$hitem" "$target/hypr/" \
|
local hname; hname="$(basename "$hitem")"
|
||||||
|| hypr_ok=false
|
[[ "$hname" == "usr" ]] && continue
|
||||||
done < <(find "$item" -maxdepth 1 -mindepth 1 -print0 | sort -z)
|
if cp -r "$hitem" "$stage/"; then
|
||||||
|
# mv can't atomically replace a non-empty dir, so clear
|
||||||
|
# an existing directory target first; files swap atomically.
|
||||||
|
[[ -d "$stage/$hname" && -d "${target}/hypr/${hname}" ]] \
|
||||||
|
&& rm -rf "${target}/hypr/${hname}"
|
||||||
|
mv -f "$stage/$hname" "${target}/hypr/${hname}" || hypr_ok=false
|
||||||
|
else
|
||||||
|
hypr_ok=false
|
||||||
|
fi
|
||||||
|
done < <(find "$item" -maxdepth 1 -mindepth 1 -print0 | sort -z)
|
||||||
|
rm -rf "$stage"
|
||||||
|
fi
|
||||||
if $hypr_ok; then
|
if $hypr_ok; then
|
||||||
ok "synced hypr ${DI}(usr/ preserved)${RS}"
|
ok "synced hypr ${DI}(usr/ preserved)${RS}"
|
||||||
(( synced++ )) || true
|
(( synced++ )) || true
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue