diff --git a/tests/update.bats b/tests/update.bats index 4338cba..41424ea 100644 --- a/tests/update.bats +++ b/tests/update.bats @@ -166,3 +166,20 @@ ran() { [ "$status" -eq 1 ] [ ! -e "$RAN" ] } + +@test "an update from before 2026-10-19 that copies this one over itself hands over to it" { + # 013acac's update: sudo cp overwrites the file bash is still reading, and + # bash reads on in the new one from where it was + [ "$(/usr/bin/git -C "$REPO" rev-parse --is-shallow-repository)" = false ] \ + || skip "needs update's history" + /usr/bin/git -C "$REPO" show 013acac:update > "$HOME/.local/bin/update" + chmod +x "$HOME/.local/bin/update" + stub sudo '[ "$1" = cp ] && exec "$@"; exit 0' + hook 10-a 'echo a >> "$RAN"' + + run "$HOME/.local/bin/update" + [ "$status" -eq 0 ] + [[ "$output" != *"command not found"* ]] + [[ "$output" == *"Done."* ]] + ran a +} diff --git a/update b/update index 402d87f..edea6c9 100755 --- a/update +++ b/update @@ -1,5 +1,29 @@ #!/bin/bash +# Updates from before 2026-10-19 (013acac's) copy this file over themselves +# while bash is still reading them, then read on from byte 1484 of the new copy. +# The exec line below starts at exactly that byte, so they run this update +# afresh; the rest of the block pads it into place, and in a normal run the +# block is a here-document nothing reads. Keep the exec line at byte 1484: +# tests/update.bats checks it. +: << 'FROM_OLD_UPDATE' +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +This block is padding for old updates. This block is padding for old updates. +................... +exec ~/.local/bin/update +FROM_OLD_UPDATE + # The whole script is wrapped in { ...; exit; } so bash parses all of it before # running anything. That way, replacing this file mid-run (e.g. by git pull and # the copy below) can't make the running copy read a mix of old and new text.