From bf4aac95adf0e8c5055ba054bd7fb9f8bd8d185f Mon Sep 17 00:00:00 2001 From: Eric van Riet Paap Date: Thu, 30 Jul 2026 00:47:27 +0200 Subject: [PATCH] Warn when disk space is low before updating in Quattro (#6432) * Warn when disk space is low before updating * Simplify update free space warning * Stop updates without enough free space * Allow forcing updates with low disk space --------- Co-authored-by: David Heinemeier Hansson --- bin/omarchy-update | 2 + bin/omarchy-update-requires-free-space | 17 +++ docs/update-process.md | 5 + test/shell.d/update-disk-space-test.sh | 138 +++++++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100755 bin/omarchy-update-requires-free-space create mode 100644 test/shell.d/update-disk-space-test.sh diff --git a/bin/omarchy-update b/bin/omarchy-update index 82064293..a1ae5942 100755 --- a/bin/omarchy-update +++ b/bin/omarchy-update @@ -102,6 +102,8 @@ run_update_pipeline() { acquire_update_lock +omarchy-update-requires-free-space + trap restore_update_inhibitors EXIT trap 'echo ""; echo -e "\033[0;31mSomething went wrong during the update!\n\nPlease review the output above carefully, correct the error, and retry the update.\n\nIf you need assistance, get help from the community at https://omarchy.org/discord\033[0m"' ERR diff --git a/bin/omarchy-update-requires-free-space b/bin/omarchy-update-requires-free-space new file mode 100755 index 00000000..07523eb2 --- /dev/null +++ b/bin/omarchy-update-requires-free-space @@ -0,0 +1,17 @@ +#!/bin/bash + +# omarchy:summary=Check free disk space required for an update +# omarchy:hidden=true + +set -e + +if [[ ${OMARCHY_UPDATE_FORCE:-0} == "1" ]]; then + exit 0 +elif read -r available_bytes < <(df --output=avail --block-size=1 / 2>/dev/null | tail -n 1) && + [[ $available_bytes =~ ^[0-9]+$ ]] && + (( available_bytes < 10 * 1024 * 1024 * 1024 )); then + echo "You need at least 10 GiB free to safely update Omarchy." + exit 1 +else + exit 0 +fi diff --git a/docs/update-process.md b/docs/update-process.md index 5081ffaa..9a0825c8 100644 --- a/docs/update-process.md +++ b/docs/update-process.md @@ -114,6 +114,8 @@ High-level flow: omarchy-update ├─ ensure transcript logging through script(1) → /tmp/omarchy-update.log ├─ acquire update lock + ├─ omarchy-update-requires-free-space + │ └─ check free space on / and warn below the configured threshold ├─ confirm unless -y ├─ create snapper snapshot, if snapper is installed └─ run update pipeline @@ -136,6 +138,9 @@ Important behavior: - In dev-link mode, `omarchy update` fast-forwards the active checkout from its configured upstream before changing system packages or running migrations. +- The free-space requirement uses a 10 GiB threshold and stops the update before + confirmation when it is not met. If free space cannot be determined, the + check is silently skipped. Set `OMARCHY_UPDATE_FORCE=1` to bypass the check. - `omarchy update` checks/runs migrations in the same visible terminal via `omarchy-migrate` after pacman finishes. - A failure should leave enough output in `/tmp/omarchy-update.log` and the diff --git a/test/shell.d/update-disk-space-test.sh b/test/shell.d/update-disk-space-test.sh new file mode 100644 index 00000000..b96df48e --- /dev/null +++ b/test/shell.d/update-disk-space-test.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +set -euo pipefail + +source "$(dirname "$0")/base-test.sh" + +unset GUM_STATUS +unset OMARCHY_UPDATE_FORCE +unset TEST_AVAILABLE_BYTES +unset TEST_DF_INVALID + +test_tmp=$(mktemp -d) +trap 'rm -rf "$test_tmp"' EXIT + +stub_bin="$test_tmp/bin" +test_home="$test_tmp/home" +runtime_dir="$test_tmp/runtime" +snapshot_marker="$test_tmp/snapshot" +gum_marker="$test_tmp/gum" +mkdir -p "$stub_bin" "$test_home" "$runtime_dir" + +run_update() { + HOME="$test_home" \ + XDG_RUNTIME_DIR="$runtime_dir" \ + PATH="$stub_bin:$ROOT/bin:$PATH" \ + LC_ALL=C \ + OMARCHY_UPDATE_LOGGED=1 \ + TEST_AVAILABLE_BYTES=${TEST_AVAILABLE_BYTES:-$((9 * 1024 * 1024 * 1024))} \ + TEST_DF_INVALID=${TEST_DF_INVALID:-0} \ + SNAPSHOT_MARKER="$snapshot_marker" \ + GUM_MARKER="$gum_marker" \ + GUM_STATUS=${GUM_STATUS:-1} \ + "$ROOT/bin/omarchy-update" "$@" +} + +write_stub() { + local name="$1" + local body="$2" + + cat >"$stub_bin/$name" <>"$GUM_MARKER" +if [[ ${1:-} == "confirm" ]]; then + exit "$GUM_STATUS" +fi +exit 0' + +write_stub omarchy-snapshot ' +touch "$SNAPSHOT_MARKER" +exit 0' + +for command in \ + omarchy-cmd-present \ + omarchy-toggle-idle \ + systemd-inhibit \ + omarchy-update-dev \ + omarchy-update-keyring \ + omarchy-update-system-pkgs \ + omarchy-migrate \ + omarchy-update-aur-pkgs \ + omarchy-update-mise \ + omarchy-update-orphan-pkgs \ + omarchy-hook \ + omarchy-update-analyze-logs \ + omarchy-shell \ + omarchy-update-restart; do + write_stub "$command" 'exit 0' +done +write_stub omarchy-update-available 'exit 1' + +set +e +TEST_AVAILABLE_BYTES=$((9 * 1024 * 1024 * 1024)) \ + PATH="$stub_bin:$ROOT/bin:$PATH" \ + "$ROOT/bin/omarchy-update-requires-free-space" >/dev/null +status=$? +set -e +(( status == 1 )) || fail "free-space helper exits non-zero when disk space is low" +pass "free-space helper reports low disk space through its exit status" + +set +e +output=$(run_update -y) +status=$? +set -e +(( status == 1 )) || fail "non-interactive update exits non-zero with low disk space" +[[ $output == *"You need at least 10 GiB free to safely update Omarchy."* ]] || fail "low disk space emits a warning" +[[ ! -f $gum_marker ]] || fail "non-interactive update does not prompt for low disk space" +[[ ! -f $snapshot_marker ]] || fail "non-interactive update stops before snapshotting with low disk space" +pass "non-interactive update stops with low disk space" + +rm -f "$snapshot_marker" "$gum_marker" +set +e +output=$(run_update) +status=$? +set -e +(( status == 1 )) || fail "interactive update exits non-zero with low disk space" +[[ $output == *"You need at least 10 GiB free to safely update Omarchy."* ]] || fail "interactive low-space update explains the requirement" +[[ ! -f $gum_marker ]] || fail "interactive update stops before confirmation with low disk space" +[[ ! -f $snapshot_marker ]] || fail "interactive update stops before snapshotting with low disk space" +pass "interactive update stops before confirmation with low disk space" + +rm -f "$snapshot_marker" "$gum_marker" +output=$(OMARCHY_UPDATE_FORCE=1 run_update -y) +[[ -z $output ]] || fail "forced update does not emit the free-space warning" +[[ ! -f $gum_marker ]] || fail "forced non-interactive update does not prompt" +[[ -f $snapshot_marker ]] || fail "forced update continues with low disk space" +pass "forced update skips the free-space requirement" + +rm -f "$snapshot_marker" "$gum_marker" +output=$(TEST_AVAILABLE_BYTES=$((10 * 1024 * 1024 * 1024)) run_update -y) +[[ $output != *"You need at least 10 GiB free"* ]] || fail "space equal to the threshold does not produce a warning" +[[ -f $snapshot_marker ]] || fail "space equal to the threshold allows the update" +pass "disk-space threshold includes the exact boundary" + +rm -f "$snapshot_marker" "$gum_marker" +GUM_STATUS=0 TEST_AVAILABLE_BYTES=$((10 * 1024 * 1024 * 1024)) run_update >/dev/null +grep -q "confirm Continue with update?" "$gum_marker" || + fail "interactive update with enough space uses the normal confirmation prompt" +[[ -f $snapshot_marker ]] || fail "accepting the normal confirmation starts the update" +pass "interactive update keeps the normal confirmation prompt when space is sufficient" + +rm -f "$snapshot_marker" +output=$(TEST_DF_INVALID=1 run_update -y) +[[ -z $output ]] || fail "failed disk-space detection remains silent" +[[ -f $snapshot_marker ]] || fail "failed disk-space detection does not block the update" +pass "failed disk-space detection silently continues"