Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
243115ea19 | ||
|
|
9fd2458d20 | ||
|
|
f593cc1933 | ||
|
|
20fbadbc95 | ||
|
|
e42fb4f61c | ||
|
|
459cbbf8e7 |
No files matched your search
@@ -5,7 +5,10 @@
|
|||||||
# targets degrade to a no-op when msgfmt/scdoc are missing, so the tree stays
|
# targets degrade to a no-op when msgfmt/scdoc are missing, so the tree stays
|
||||||
# usable for development without the build dependencies installed.
|
# usable for development without the build dependencies installed.
|
||||||
|
|
||||||
VERSION := 1.0.0
|
# Overridable so a packager can pass the version it is actually building
|
||||||
|
# (`make VERSION=$pkgver`). The literal below is the fallback for builds
|
||||||
|
# straight from a checkout, and is what a release tag has to carry.
|
||||||
|
VERSION ?= 1.0.6
|
||||||
|
|
||||||
PREFIX ?= /usr
|
PREFIX ?= /usr
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ msgstr ""
|
|||||||
msgid "Quit"
|
msgid "Quit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Press Enter to continue..."
|
msgid "Press any key to continue..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. Commands
|
#. Commands
|
||||||
@@ -243,3 +243,17 @@ msgstr ""
|
|||||||
|
|
||||||
msgid "pacman's lock file looks left over from an interrupted update. Updates are paused until it is cleared."
|
msgid "pacman's lock file looks left over from an interrupted update. Updates are paused until it is cleared."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Some packages were held back"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, c-format
|
||||||
|
msgid "%s could not be updated and was skipped. Everything else is up to date."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, c-format
|
||||||
|
msgid "Held back: %s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The last run was stopped before it finished."
|
||||||
|
msgstr ""
|
||||||
@@ -135,8 +135,8 @@ msgstr "Aktuelle Bedingungen anzeigen"
|
|||||||
msgid "Quit"
|
msgid "Quit"
|
||||||
msgstr "Beenden"
|
msgstr "Beenden"
|
||||||
|
|
||||||
msgid "Press Enter to continue..."
|
msgid "Press any key to continue..."
|
||||||
msgstr "Zum Fortfahren Enter drücken …"
|
msgstr "Zum Fortfahren eine Taste drücken …"
|
||||||
|
|
||||||
#. Commands
|
#. Commands
|
||||||
msgid "Automatic updates are on."
|
msgid "Automatic updates are on."
|
||||||
@@ -244,3 +244,17 @@ msgstr "Paketdatenbank gesperrt"
|
|||||||
|
|
||||||
msgid "pacman's lock file looks left over from an interrupted update. Updates are paused until it is cleared."
|
msgid "pacman's lock file looks left over from an interrupted update. Updates are paused until it is cleared."
|
||||||
msgstr "Die Sperrdatei von pacman scheint von einem abgebrochenen Update übrig zu sein. Bis sie entfernt ist, pausieren die Updates."
|
msgstr "Die Sperrdatei von pacman scheint von einem abgebrochenen Update übrig zu sein. Bis sie entfernt ist, pausieren die Updates."
|
||||||
|
|
||||||
|
msgid "Some packages were held back"
|
||||||
|
msgstr "Einige Pakete wurden zurückgehalten"
|
||||||
|
|
||||||
|
#, c-format
|
||||||
|
msgid "%s could not be updated and was skipped. Everything else is up to date."
|
||||||
|
msgstr "%s konnte nicht aktualisiert werden und wurde übersprungen. Alles andere ist aktuell."
|
||||||
|
|
||||||
|
#, c-format
|
||||||
|
msgid "Held back: %s"
|
||||||
|
msgstr "Zurückgehalten: %s"
|
||||||
|
|
||||||
|
msgid "The last run was stopped before it finished."
|
||||||
|
msgstr "Der letzte Lauf wurde abgebrochen, bevor er fertig war."
|
||||||
@@ -170,7 +170,9 @@ cau_do_status() {
|
|||||||
|
|
||||||
cau_do_run() {
|
cau_do_run() {
|
||||||
cau_need_root
|
cau_need_root
|
||||||
exec "$CAU_LIBEXECDIR/cachy-auto-update-run" "$@"
|
# Not exec'd: this is also called from the menu, which has to survive the
|
||||||
|
# run and redraw afterwards.
|
||||||
|
"$CAU_LIBEXECDIR/cachy-auto-update-run" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
cau_do_log() {
|
cau_do_log() {
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ if [[ $EUID -ne 0 ]]; then
|
|||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Force a neutral locale here rather than relying on the unit's Environment=,
|
||||||
|
# so a run started by hand behaves exactly like one started by the timer.
|
||||||
|
# pacman failures are classified by matching its output, and on a German system
|
||||||
|
# that output is German. Text aimed at a person does not come through here - a
|
||||||
|
# notification is rendered in the recipient's own locale by cau_msg_in.
|
||||||
|
export LC_ALL=C LANGUAGE=
|
||||||
|
|
||||||
# Re-exec under an inhibitor so a suspend or shutdown cannot land in the middle
|
# Re-exec under an inhibitor so a suspend or shutdown cannot land in the middle
|
||||||
# of a pacman transaction and leave the database half-written. Done before
|
# of a pacman transaction and leave the database half-written. Done before
|
||||||
# anything else so the whole pass is covered, including the lock.
|
# anything else so the whole pass is covered, including the lock.
|
||||||
@@ -56,6 +63,21 @@ fi
|
|||||||
cau_config_load
|
cau_config_load
|
||||||
cau_log_open
|
cau_log_open
|
||||||
|
|
||||||
|
# Record an interruption rather than leaving the previous run's verdict behind.
|
||||||
|
# Without this, killing an interactive run leaves last_result at whatever it was
|
||||||
|
# before - so the menu can keep reporting a problem from hours ago while the
|
||||||
|
# machine is in fact fully up to date, which is worse than saying nothing.
|
||||||
|
# pacman makes the commit phase itself uninterruptible, so the packages either
|
||||||
|
# all landed or none did; only our own bookkeeping is at risk here.
|
||||||
|
_cau_interrupted() {
|
||||||
|
cau_error "Update run interrupted ($1)"
|
||||||
|
cau_state_write last_result interrupted
|
||||||
|
exit 130
|
||||||
|
}
|
||||||
|
trap '_cau_interrupted SIGINT' INT
|
||||||
|
trap '_cau_interrupted SIGTERM' TERM
|
||||||
|
trap '_cau_interrupted SIGHUP' HUP
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Should this run happen at all?
|
# Should this run happen at all?
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -195,6 +217,22 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Packages skipped so the rest of the upgrade could proceed. The notification
|
||||||
|
# only fires when the set changes: a blocker waiting on an upstream fix would
|
||||||
|
# otherwise produce the same message every single day.
|
||||||
|
prev_held="$(cau_state_read held_back '')"
|
||||||
|
if [[ -n $CAU_PACMAN_HELD ]]; then
|
||||||
|
cau_state_write held_back "$CAU_PACMAN_HELD"
|
||||||
|
cau_warn "Held back: $CAU_PACMAN_HELD"
|
||||||
|
if [[ $CAU_PACMAN_HELD != "$prev_held" && $CFG_NOTIFY_ERROR == yes ]]; then
|
||||||
|
cau_notify normal "Some packages were held back" \
|
||||||
|
"%s could not be updated and was skipped. Everything else is up to date." \
|
||||||
|
"$CAU_PACMAN_HELD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cau_state_clear held_back
|
||||||
|
fi
|
||||||
|
|
||||||
if cau_pacman_reboot_needed; then
|
if cau_pacman_reboot_needed; then
|
||||||
cau_state_write reboot_needed 1
|
cau_state_write reboot_needed 1
|
||||||
cau_info "A kernel update needs a restart"
|
cau_info "A kernel update needs a restart"
|
||||||
|
|||||||
+27
-4
@@ -91,7 +91,14 @@ cau_msg_in() {
|
|||||||
# Output and logging
|
# Output and logging
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
if [[ -t 1 && -z ${NO_COLOR:-} ]]; then
|
# Is a person watching? Decided once, here, while stdout is still whatever the
|
||||||
|
# process was started with. Testing `-t 1` at the point of use is unreliable:
|
||||||
|
# any function called through $(...) or <(...) sees a pipe on stdout and would
|
||||||
|
# conclude nobody is there.
|
||||||
|
CAU_INTERACTIVE=''
|
||||||
|
[[ -t 1 ]] && CAU_INTERACTIVE=1
|
||||||
|
|
||||||
|
if [[ -n $CAU_INTERACTIVE && -z ${NO_COLOR:-} ]]; then
|
||||||
CAU_C_RESET=$'\033[0m'
|
CAU_C_RESET=$'\033[0m'
|
||||||
CAU_C_BOLD=$'\033[1m'
|
CAU_C_BOLD=$'\033[1m'
|
||||||
CAU_C_DIM=$'\033[2m'
|
CAU_C_DIM=$'\033[2m'
|
||||||
@@ -132,10 +139,19 @@ cau_log_open() {
|
|||||||
CAU_LOG_OPEN=1
|
CAU_LOG_OPEN=1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Runs a command, streaming its combined output into the run log. Returns the
|
# Runs a command, capturing its combined output in the run log. Returns the
|
||||||
# command's exit status.
|
# command's exit status.
|
||||||
|
#
|
||||||
|
# When a person is watching - `cachy-auto-update run` from a terminal - the
|
||||||
|
# output is shown as well. Building an AUR package or pulling a few hundred
|
||||||
|
# megabytes of Flatpak can take minutes, and silence for that long is
|
||||||
|
# indistinguishable from a hang.
|
||||||
cau_run_logged() {
|
cau_run_logged() {
|
||||||
if [[ -n ${CAU_LOG_OPEN:-} ]]; then
|
if [[ -n ${CAU_LOG_OPEN:-} ]]; then
|
||||||
|
if [[ -n $CAU_INTERACTIVE ]]; then
|
||||||
|
"$@" 2>&1 | tee -a "$CAU_RUNLOG"
|
||||||
|
return "${PIPESTATUS[0]}"
|
||||||
|
fi
|
||||||
"$@" >> "$CAU_RUNLOG" 2>&1
|
"$@" >> "$CAU_RUNLOG" 2>&1
|
||||||
else
|
else
|
||||||
"$@" >&2
|
"$@" >&2
|
||||||
@@ -146,11 +162,18 @@ cau_run_logged() {
|
|||||||
# Terminal helpers for the CLI
|
# Terminal helpers for the CLI
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Set by cau_bad and cau_note. The menu redraws immediately after an action,
|
||||||
|
# which would wipe the screen; this marks that something was printed that the
|
||||||
|
# user still has to read, so only those cases wait for a keypress. A plain
|
||||||
|
# success needs no acknowledgement - the status block at the top of the menu
|
||||||
|
# already shows the new state.
|
||||||
|
CAU_UI_NEEDS_ACK=''
|
||||||
|
|
||||||
cau_say() { printf '%s\n' "$*"; }
|
cau_say() { printf '%s\n' "$*"; }
|
||||||
cau_head() { printf '\n%s%s%s\n\n' "$CAU_C_BOLD$CAU_C_BLUE" "$*" "$CAU_C_RESET"; }
|
cau_head() { printf '\n%s%s%s\n\n' "$CAU_C_BOLD$CAU_C_BLUE" "$*" "$CAU_C_RESET"; }
|
||||||
cau_ok() { printf '%s✔%s %s\n' "$CAU_C_GREEN" "$CAU_C_RESET" "$*"; }
|
cau_ok() { printf '%s✔%s %s\n' "$CAU_C_GREEN" "$CAU_C_RESET" "$*"; }
|
||||||
cau_bad() { printf '%s✘%s %s\n' "$CAU_C_RED" "$CAU_C_RESET" "$*" >&2; }
|
cau_bad() { CAU_UI_NEEDS_ACK=1; printf '%s✘%s %s\n' "$CAU_C_RED" "$CAU_C_RESET" "$*" >&2; }
|
||||||
cau_note() { printf '%s•%s %s\n' "$CAU_C_DIM" "$CAU_C_RESET" "$*"; }
|
cau_note() { CAU_UI_NEEDS_ACK=1; printf '%s•%s %s\n' "$CAU_C_DIM" "$CAU_C_RESET" "$*"; }
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# State files
|
# State files
|
||||||
|
|||||||
+35
-6
@@ -81,12 +81,23 @@ cau_ui_status() {
|
|||||||
printf '\n %s%s%s\n' "$CAU_C_YELLOW" \
|
printf '\n %s%s%s\n' "$CAU_C_YELLOW" \
|
||||||
"$(cau_msg "The last run reported a problem - see 'cachy-auto-update log'.")" \
|
"$(cau_msg "The last run reported a problem - see 'cachy-auto-update log'.")" \
|
||||||
"$CAU_C_RESET"
|
"$CAU_C_RESET"
|
||||||
|
elif [[ $result == interrupted ]]; then
|
||||||
|
printf '\n %s%s%s\n' "$CAU_C_YELLOW" \
|
||||||
|
"$(cau_msg "The last run was stopped before it finished.")" \
|
||||||
|
"$CAU_C_RESET"
|
||||||
fi
|
fi
|
||||||
if [[ $reboot == 1 ]]; then
|
if [[ $reboot == 1 ]]; then
|
||||||
printf '\n %s%s%s\n' "$CAU_C_YELLOW" \
|
printf '\n %s%s%s\n' "$CAU_C_YELLOW" \
|
||||||
"$(cau_msg "A restart is recommended to finish a kernel update.")" \
|
"$(cau_msg "A restart is recommended to finish a kernel update.")" \
|
||||||
"$CAU_C_RESET"
|
"$CAU_C_RESET"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local held
|
||||||
|
held="$(cau_state_read held_back '')"
|
||||||
|
if [[ -n $held ]]; then
|
||||||
|
printf '\n %s%s%s\n' "$CAU_C_YELLOW" \
|
||||||
|
"$(cau_msg "Held back: %s" "$held")" "$CAU_C_RESET"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# cau_ui_status_conditions
|
# cau_ui_status_conditions
|
||||||
@@ -145,31 +156,49 @@ cau_ui_menu() {
|
|||||||
printf ' [q] %s\n' "$(cau_msg "Quit")"
|
printf ' [q] %s\n' "$(cau_msg "Quit")"
|
||||||
printf '\n > '
|
printf '\n > '
|
||||||
|
|
||||||
read -r choice || { printf '\n'; return 0; }
|
# One keypress, no Enter. -s keeps the raw character out of the
|
||||||
|
# display so the echo below is the only thing printed, and a failing
|
||||||
|
# read means EOF (Ctrl-D, or a script piping input) - that quits.
|
||||||
|
read -rsn1 choice || { printf '\n'; return 0; }
|
||||||
|
printf '%s\n' "$choice"
|
||||||
|
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
|
# The two switches flip and return straight to the menu, where the
|
||||||
|
# status block shows the result. Only a warning or an error holds
|
||||||
|
# the screen (see CAU_UI_NEEDS_ACK).
|
||||||
1)
|
1)
|
||||||
|
CAU_UI_NEEDS_ACK=''
|
||||||
if [[ $CFG_ENABLED == yes ]]; then cau_do_disable; else cau_do_enable; fi
|
if [[ $CFG_ENABLED == yes ]]; then cau_do_disable; else cau_do_enable; fi
|
||||||
cau_pause
|
if [[ -n $CAU_UI_NEEDS_ACK ]]; then cau_pause; fi
|
||||||
;;
|
;;
|
||||||
2)
|
2)
|
||||||
|
CAU_UI_NEEDS_ACK=''
|
||||||
if [[ $CFG_NOTIFICATIONS == yes ]]; then
|
if [[ $CFG_NOTIFICATIONS == yes ]]; then
|
||||||
cau_do_notifications off
|
cau_do_notifications off
|
||||||
else
|
else
|
||||||
cau_do_notifications on
|
cau_do_notifications on
|
||||||
fi
|
fi
|
||||||
cau_pause
|
if [[ -n $CAU_UI_NEEDS_ACK ]]; then cau_pause; fi
|
||||||
;;
|
;;
|
||||||
3) cau_do_run --force; cau_pause ;;
|
3) cau_do_run --force; cau_pause ;;
|
||||||
4) cau_do_log; cau_pause ;;
|
4) cau_do_log; cau_pause ;;
|
||||||
5) cau_ui_status_conditions; cau_pause ;;
|
5) cau_ui_status_conditions; cau_pause ;;
|
||||||
q|Q|'') return 0 ;;
|
q|Q) return 0 ;;
|
||||||
|
$'\e')
|
||||||
|
# Arrow keys and friends arrive as ESC [ X. Swallow the rest so
|
||||||
|
# one keypress does not redraw the menu three times. Escape is
|
||||||
|
# deliberately not a quit key: that would make a stray arrow
|
||||||
|
# key close the menu.
|
||||||
|
read -rsn2 -t 0.05 _ 2>/dev/null || true
|
||||||
|
;;
|
||||||
|
# Anything else, Enter included, just redraws.
|
||||||
*) ;;
|
*) ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
cau_pause() {
|
cau_pause() {
|
||||||
printf '\n %s' "$(cau_msg "Press Enter to continue...")"
|
printf '\n %s' "$(cau_msg "Press any key to continue...")"
|
||||||
read -r _ || true
|
read -rsn1 _ || true
|
||||||
|
printf '\n'
|
||||||
}
|
}
|
||||||
+96
-19
@@ -10,15 +10,40 @@
|
|||||||
CAU_PACMAN_COUNT=0
|
CAU_PACMAN_COUNT=0
|
||||||
CAU_PACMAN_PENDING=''
|
CAU_PACMAN_PENDING=''
|
||||||
|
|
||||||
|
# Packages that had to be skipped so the rest of the upgrade could go through.
|
||||||
|
CAU_PACMAN_HELD=''
|
||||||
|
|
||||||
# Base flags for every unattended pacman invocation.
|
# Base flags for every unattended pacman invocation.
|
||||||
cau_pacman_flags() {
|
cau_pacman_flags() {
|
||||||
printf '%s\n' --noconfirm --color never --noprogressbar --disable-download-timeout
|
printf '%s\n' --noconfirm --color never --disable-download-timeout
|
||||||
|
|
||||||
|
# A progress bar is worth having when somebody is watching a `run` from a
|
||||||
|
# terminal; in the timer's log it is only carriage-return noise.
|
||||||
|
[[ -n $CAU_INTERACTIVE ]] || printf '%s\n' --noprogressbar
|
||||||
|
|
||||||
local pkg
|
local pkg
|
||||||
for pkg in $CFG_IGNORE_PKG; do
|
for pkg in $CFG_IGNORE_PKG; do
|
||||||
printf '%s\n' --ignore "$pkg"
|
printf '%s\n' --ignore "$pkg"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# _cau_pacman_exec <logfile> <pacman args...>
|
||||||
|
# Captures pacman's output for classification, and streams it as well when a
|
||||||
|
# person is watching. Upgrading a few hundred packages takes minutes; without
|
||||||
|
# this an interactive run shows one line and then nothing at all, which is
|
||||||
|
# indistinguishable from a hang and invites someone to kill it mid-transaction.
|
||||||
|
_cau_pacman_exec() {
|
||||||
|
local log="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ -n $CAU_INTERACTIVE ]]; then
|
||||||
|
pacman "$@" 2>&1 | tee "$log"
|
||||||
|
return "${PIPESTATUS[0]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pacman "$@" > "$log" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
# cau_pacman_pending
|
# cau_pacman_pending
|
||||||
# Fills CAU_PACMAN_PENDING and returns 1 when there is nothing to do.
|
# Fills CAU_PACMAN_PENDING and returns 1 when there is nothing to do.
|
||||||
cau_pacman_pending() {
|
cau_pacman_pending() {
|
||||||
@@ -55,6 +80,8 @@ _cau_pacman_classify() {
|
|||||||
|
|
||||||
if grep -qiE 'are in conflict|unresolvable package conflicts' "$log"; then
|
if grep -qiE 'are in conflict|unresolvable package conflicts' "$log"; then
|
||||||
printf 'conflict\n'
|
printf 'conflict\n'
|
||||||
|
elif grep -qiE 'could not satisfy dependencies|breaks dependency|unable to satisfy dependency' "$log"; then
|
||||||
|
printf 'dependency\n'
|
||||||
elif grep -qiE 'signature from .* is (unknown trust|marginal trust|invalid)|invalid or corrupted package \(PGP signature\)|key ".*" is unknown|keyring is not writable' "$log"; then
|
elif grep -qiE 'signature from .* is (unknown trust|marginal trust|invalid)|invalid or corrupted package \(PGP signature\)|key ".*" is unknown|keyring is not writable' "$log"; then
|
||||||
printf 'keyring\n'
|
printf 'keyring\n'
|
||||||
elif grep -qiE 'exists in filesystem' "$log"; then
|
elif grep -qiE 'exists in filesystem' "$log"; then
|
||||||
@@ -64,6 +91,25 @@ _cau_pacman_classify() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# _cau_pacman_blockers <logfile>
|
||||||
|
# The packages standing in the way of an otherwise fine upgrade. pacman names
|
||||||
|
# them in its dependency errors:
|
||||||
|
#
|
||||||
|
# :: removing libperconaserverclient breaks dependency 'libperconaserverclient'
|
||||||
|
# required by heidisql-qt6-bin
|
||||||
|
# :: unable to satisfy dependency 'foo' required by bar
|
||||||
|
#
|
||||||
|
# In the first form the package being removed is the one to keep; in the second
|
||||||
|
# it is the package that cannot be installed.
|
||||||
|
_cau_pacman_blockers() {
|
||||||
|
local log="$1"
|
||||||
|
|
||||||
|
{
|
||||||
|
sed -nE "s/.*removing ([^ ]+) breaks dependency.*/\\1/p" "$log"
|
||||||
|
sed -nE "s/.*unable to satisfy dependency '[^']*' required by ([^ ]+).*/\\1/p" "$log"
|
||||||
|
} | grep -E '^[A-Za-z0-9@._+-]+$' | sort -u
|
||||||
|
}
|
||||||
|
|
||||||
# cau_pacman_update
|
# cau_pacman_update
|
||||||
# Returns 0 on success (including "nothing to do"), 1 on a failure the user
|
# Returns 0 on success (including "nothing to do"), 1 on a failure the user
|
||||||
# needs to hear about. CAU_PACMAN_COUNT holds how many packages moved.
|
# needs to hear about. CAU_PACMAN_COUNT holds how many packages moved.
|
||||||
@@ -76,15 +122,31 @@ cau_pacman_update() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -n $CAU_PACMAN_PENDING ]]; then
|
||||||
CAU_PACMAN_COUNT="$(grep -c . <<< "$CAU_PACMAN_PENDING")"
|
CAU_PACMAN_COUNT="$(grep -c . <<< "$CAU_PACMAN_PENDING")"
|
||||||
[[ $CAU_PACMAN_COUNT =~ ^[0-9]+$ ]] || CAU_PACMAN_COUNT=0
|
[[ $CAU_PACMAN_COUNT =~ ^[0-9]+$ ]] || CAU_PACMAN_COUNT=0
|
||||||
cau_info "Updating $CAU_PACMAN_COUNT repository package(s)"
|
cau_info "Updating $CAU_PACMAN_COUNT repository package(s)"
|
||||||
|
else
|
||||||
|
# checkupdates is unavailable, so the list is unknown and pacman is
|
||||||
|
# asked to work it out itself.
|
||||||
|
CAU_PACMAN_COUNT=0
|
||||||
|
cau_info "Running a full system upgrade (pending list unavailable)"
|
||||||
|
fi
|
||||||
|
|
||||||
mapfile -t flags < <(cau_pacman_flags)
|
mapfile -t flags < <(cau_pacman_flags)
|
||||||
log="$(mktemp)" || return 1
|
log="$(mktemp)" || return 1
|
||||||
|
|
||||||
if pacman -Syu "${flags[@]}" > "$log" 2>&1; then
|
# Recovery loop rather than a single retry: fixing one problem regularly
|
||||||
|
# uncovers the next (a conflict resolved into a dependency error, say).
|
||||||
|
# Each remedy is applied at most once, so this always terminates.
|
||||||
|
local -a extra=() blockers=() tried=()
|
||||||
|
local attempt=0 b
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
if _cau_pacman_exec "$log" -Syu "${flags[@]}" "${extra[@]}"; then
|
||||||
cat "$log" >> "$CAU_RUNLOG" 2>/dev/null
|
cat "$log" >> "$CAU_RUNLOG" 2>/dev/null
|
||||||
|
grep -E '^(removing|replacing) ' "$log" 2>/dev/null \
|
||||||
|
| while read -r line; do cau_info " $line"; done
|
||||||
rm -f "$log"
|
rm -f "$log"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -93,6 +155,11 @@ cau_pacman_update() {
|
|||||||
kind="$(_cau_pacman_classify "$log")"
|
kind="$(_cau_pacman_classify "$log")"
|
||||||
cau_warn "pacman -Syu failed ($kind)"
|
cau_warn "pacman -Syu failed ($kind)"
|
||||||
|
|
||||||
|
if (( ++attempt > 3 )) || [[ " ${tried[*]} " == *" $kind "* ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
tried+=("$kind")
|
||||||
|
|
||||||
case "$kind" in
|
case "$kind" in
|
||||||
keyring)
|
keyring)
|
||||||
# A stale keyring is the one failure that is always safe to fix
|
# A stale keyring is the one failure that is always safe to fix
|
||||||
@@ -104,12 +171,6 @@ cau_pacman_update() {
|
|||||||
if (( ${#keyrings[@]} )); then
|
if (( ${#keyrings[@]} )); then
|
||||||
cau_run_logged pacman -Sy --noconfirm --color never "${keyrings[@]}" || true
|
cau_run_logged pacman -Sy --noconfirm --color never "${keyrings[@]}" || true
|
||||||
fi
|
fi
|
||||||
if pacman -Syu "${flags[@]}" > "$log" 2>&1; then
|
|
||||||
cat "$log" >> "$CAU_RUNLOG" 2>/dev/null
|
|
||||||
rm -f "$log"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
cat "$log" >> "$CAU_RUNLOG" 2>/dev/null
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
conflict)
|
conflict)
|
||||||
@@ -119,18 +180,29 @@ cau_pacman_update() {
|
|||||||
# question bitmask: 4 = CONFLICT_PKG, 16 = REMOVE_PKGS.
|
# question bitmask: 4 = CONFLICT_PKG, 16 = REMOVE_PKGS.
|
||||||
if [[ $CFG_RESOLVE_CONFLICTS != yes ]]; then
|
if [[ $CFG_RESOLVE_CONFLICTS != yes ]]; then
|
||||||
cau_error "Package conflict requires a decision (AutoResolveConflicts is off)"
|
cau_error "Package conflict requires a decision (AutoResolveConflicts is off)"
|
||||||
rm -f "$log"
|
break
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
cau_info "Resolving package conflicts automatically and retrying"
|
cau_info "Resolving package conflicts automatically and retrying"
|
||||||
if pacman -Syu "${flags[@]}" --ask=20 > "$log" 2>&1; then
|
extra+=(--ask=20)
|
||||||
cat "$log" >> "$CAU_RUNLOG" 2>/dev/null
|
;;
|
||||||
grep -E '^(removing|replacing) ' "$log" 2>/dev/null \
|
|
||||||
| while read -r line; do cau_info " $line"; done
|
dependency)
|
||||||
rm -f "$log"
|
# Something installed still depends on a package the repos want
|
||||||
return 0
|
# to drop or replace - almost always an AUR package that has not
|
||||||
|
# caught up yet. Nothing here can fix that, and it is not worth
|
||||||
|
# failing over: letting one stuck package block every other
|
||||||
|
# update indefinitely is far worse on an unattended machine.
|
||||||
|
# Hold the blockers back and upgrade everything else.
|
||||||
|
mapfile -t blockers < <(_cau_pacman_blockers "$log")
|
||||||
|
if (( ${#blockers[@]} == 0 )); then
|
||||||
|
cau_error "Dependency problem with no package to hold back"
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
cat "$log" >> "$CAU_RUNLOG" 2>/dev/null
|
for b in "${blockers[@]}"; do
|
||||||
|
extra+=(--ignore "$b")
|
||||||
|
done
|
||||||
|
CAU_PACMAN_HELD="${blockers[*]}"
|
||||||
|
cau_warn "Holding back ${blockers[*]} and retrying without them"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
filesystem)
|
filesystem)
|
||||||
@@ -138,13 +210,18 @@ cau_pacman_update() {
|
|||||||
# silently clobber something the user put there deliberately, so
|
# silently clobber something the user put there deliberately, so
|
||||||
# this one stays a human decision.
|
# this one stays a human decision.
|
||||||
cau_error "Files on disk conflict with the update; manual review needed"
|
cau_error "Files on disk conflict with the update; manual review needed"
|
||||||
rm -f "$log"
|
break
|
||||||
return 1
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
break
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
rm -f "$log"
|
rm -f "$log"
|
||||||
CAU_PACMAN_COUNT=0
|
CAU_PACMAN_COUNT=0
|
||||||
|
CAU_PACMAN_HELD=''
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user