92 lines
3.4 KiB
Bash
Executable File
92 lines
3.4 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Retry a system package update after resolving file conflicts
|
|
# omarchy:hidden=true
|
|
|
|
# Internal to omarchy-update-system-pkgs. Not a command to run by hand: it acts
|
|
# on a pacman error report, and an old or hand-written one would move live files
|
|
# out of the way for an upgrade that is not happening.
|
|
#
|
|
# Paths written by a script rather than installed by a package -- an earlier
|
|
# release's installer, an in-place edit -- belong to nobody, and pacman refuses
|
|
# to install over a file it doesn't own. This clears them and runs the upgrade
|
|
# again.
|
|
|
|
set -e
|
|
|
|
[[ ${OMARCHY_UPDATE_CONFLICT:-} == 1 ]] || {
|
|
echo "omarchy-update-system-pkgs-when-conflicted runs as part of omarchy update" >&2
|
|
exit 1
|
|
}
|
|
|
|
errors=${1:?usage: omarchy-update-system-pkgs-when-conflicted <pacman-error-report>}
|
|
|
|
# Where a file pacman is taking over gets moved, mirroring its full path. Kept
|
|
# out of the directory it came from: SDDM reads every file in sddm.conf.d
|
|
# whatever its extension, and systemd-sleep runs every executable in
|
|
# system-sleep, so a copy left beside the original would still be live.
|
|
replaced=${OMARCHY_REPLACED_DIR:-/var/lib/omarchy/replaced}
|
|
|
|
# Anything moved that the upgrade didn't end up installing goes back, whether
|
|
# the retry failed or the move loop itself was interrupted partway. Nothing here
|
|
# should leave configuration inactive that was live when it started.
|
|
#
|
|
# -e follows symlinks, so a dangling one reads as absent. -L catches those: a
|
|
# link pacman installed, and a relative link that no longer resolves from inside
|
|
# the quarantine.
|
|
moved=()
|
|
restore_moved() {
|
|
local path restorable=()
|
|
|
|
for path in "${moved[@]}"; do
|
|
if [[ ! -e $path && ! -L $path ]] && [[ -e $replaced$path || -L $replaced$path ]]; then
|
|
restorable+=("$path")
|
|
fi
|
|
done
|
|
((${#restorable[@]})) || return 0
|
|
|
|
echo -e "\e[33m\nPutting back what the upgrade didn't take:\e[0m"
|
|
for path in "${restorable[@]}"; do
|
|
sudo mv -T "$replaced$path" "$path"
|
|
echo " $path"
|
|
done
|
|
}
|
|
|
|
# exec'd into, so the caller's EXIT trap never ran and the report is still here.
|
|
# Cleaning it up is this script's job from now on.
|
|
trap 'restore_moved; rm -f "$errors"' EXIT
|
|
trap 'exit 1' INT TERM
|
|
|
|
# Paths one of these packages installs that pacman doesn't own. Moving them out
|
|
# of the way is what lets the upgrade through, and works on a leftover directory
|
|
# as well as a file.
|
|
#
|
|
# "pkg: /path exists in filesystem" is unowned; the same line plus "(owned by
|
|
# x)" is not, so the end anchor takes only ours. -Qo re-checks the live database
|
|
# before anything moves.
|
|
mapfile -t leftovers < <(
|
|
grep -oP '^omarchy(-dev|-settings|-settings-dev)?: \K.+(?= exists in filesystem$)' "$errors" |
|
|
while IFS= read -r path; do pacman -Qo "$path" &>/dev/null || echo "$path"; done
|
|
)
|
|
((${#leftovers[@]})) || exit 1
|
|
|
|
# All of them or none: moving a subset leaves the retry blocked by the rest, and
|
|
# the moved files inactive for nothing.
|
|
((${#leftovers[@]} == $(grep -c ' exists in filesystem' "$errors"))) || exit 1
|
|
|
|
echo -e "\e[33m\nTaking over files pacman doesn't own yet:\e[0m"
|
|
for path in "${leftovers[@]}"; do
|
|
sudo mkdir -p "$replaced${path%/*}"
|
|
# -T so an existing directory at the destination is replaced, not moved into.
|
|
sudo mv -T --backup=numbered "$path" "$replaced$path"
|
|
moved+=("$path")
|
|
echo " $path -> $replaced$path"
|
|
done
|
|
echo
|
|
|
|
if OMARCHY_UPDATE_RETRY=1 omarchy-update-system-pkgs; then
|
|
moved=()
|
|
exit 0
|
|
fi
|
|
exit 1
|