diff --git a/Makefile b/Makefile index 395325c..43ede36 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ # 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.5 +VERSION ?= 1.0.6 PREFIX ?= /usr DESTDIR ?= diff --git a/po/cachy-auto-update.pot b/po/cachy-auto-update.pot index 073ed7f..1c13b92 100644 --- a/po/cachy-auto-update.pot +++ b/po/cachy-auto-update.pot @@ -254,3 +254,6 @@ msgstr "" #, c-format msgid "Held back: %s" msgstr "" + +msgid "The last run was stopped before it finished." +msgstr "" diff --git a/po/de.po b/po/de.po index 261b8fa..e6c80d0 100644 --- a/po/de.po +++ b/po/de.po @@ -255,3 +255,6 @@ msgstr "%s konnte nicht aktualisiert werden und wurde übersprungen. Alles ander #, 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." diff --git a/src/cachy-auto-update-run b/src/cachy-auto-update-run index 45fd9cd..9c5e8b9 100644 --- a/src/cachy-auto-update-run +++ b/src/cachy-auto-update-run @@ -63,6 +63,21 @@ fi cau_config_load 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? # --------------------------------------------------------------------------- diff --git a/src/lib/common.sh b/src/lib/common.sh index 2e00bb8..d64358d 100644 --- a/src/lib/common.sh +++ b/src/lib/common.sh @@ -91,7 +91,14 @@ cau_msg_in() { # 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_BOLD=$'\033[1m' CAU_C_DIM=$'\033[2m' @@ -132,10 +139,19 @@ cau_log_open() { 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. +# +# 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() { 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 else "$@" >&2 diff --git a/src/lib/menu.sh b/src/lib/menu.sh index 441b70c..42812f6 100644 --- a/src/lib/menu.sh +++ b/src/lib/menu.sh @@ -81,6 +81,10 @@ cau_ui_status() { printf '\n %s%s%s\n' "$CAU_C_YELLOW" \ "$(cau_msg "The last run reported a problem - see 'cachy-auto-update log'.")" \ "$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 if [[ $reboot == 1 ]]; then printf '\n %s%s%s\n' "$CAU_C_YELLOW" \ diff --git a/src/lib/pkg_pacman.sh b/src/lib/pkg_pacman.sh index 2ba468f..7cf6fc3 100644 --- a/src/lib/pkg_pacman.sh +++ b/src/lib/pkg_pacman.sh @@ -15,13 +15,35 @@ CAU_PACMAN_HELD='' # Base flags for every unattended pacman invocation. 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 for pkg in $CFG_IGNORE_PKG; do printf '%s\n' --ignore "$pkg" done } +# _cau_pacman_exec +# 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 # Fills CAU_PACMAN_PENDING and returns 1 when there is nothing to do. cau_pacman_pending() { @@ -121,7 +143,7 @@ cau_pacman_update() { local attempt=0 b while true; do - if pacman -Syu "${flags[@]}" "${extra[@]}" > "$log" 2>&1; then + if _cau_pacman_exec "$log" -Syu "${flags[@]}" "${extra[@]}"; then cat "$log" >> "$CAU_RUNLOG" 2>/dev/null grep -E '^(removing|replacing) ' "$log" 2>/dev/null \ | while read -r line; do cau_info " $line"; done