Skip to content

feat(cli): stream update downloads with live progress - #40

Merged
damusix merged 4 commits into
mainfrom
update-download-progress
Sep 9, 2026
Merged

feat(cli): stream update downloads with live progress#40
damusix merged 4 commits into
mainfrom
update-download-progress

Conversation

@damusix

@damusix damusix commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

ignatius update buffered the entire ~73MB binary with arrayBuffer() and printed one static Downloading ignatius <version>… line, so the download looked identical to a hang and peaked at the asset's full size in memory.

It now streams the asset chunk-wise to the staging file, counting bytes as they arrive and rewriting one status line in place:

Downloading 41.9 / 73.2 MB (57%)
Downloaded 73.2 MB (100%)

The mechanism is the one atomic already ships and noorm already uses: count bytes off the response body, fire a callback every 512KB. No timer, no stat() polling. sha256 is computed incrementally over the same chunks, so the file is never read twice and never held in memory.

Off a TTY the renderer is null and one static line prints instead, because without \r rewriting every tick would print its own line into redirected output.

Also closes a gap: previously only a rename failure cleaned up the staging file, so a failed or aborted download could strand a partial binary next to the real one. A failed download, a checksum mismatch, and a failed rename now all clean up.

Unchanged, deliberately: checksum verification still runs after the download and before the rename, an unreachable checksums.txt is still non-fatal, a genuine mismatch still aborts, and Windows still gets the manual-download message.

Verification

Full suite green, 1259 assertions. The pure renderer is unit-tested for all five branches.

Beyond that, a real self-update was executed twice against the live GitHub release: dist/ignatius was copied to a throwaway path and ran update --yes against it. Progress advanced 0% to 100%, the checksum verified, the binary swapped 0.17.0 to 0.19.0 and reported the new version, and no staging file was left behind. The non-TTY path printed one line and no progress output.

Not in scope

The download still has no stall watchdog. A bare fetch() can hang forever if a connection opens and goes silent; atomic and noorm both abort after 30s of no bytes. Streaming makes that hang more visible but does not fix it. Left out deliberately, since the ask was the indicator, and noted in the branch scratchpad.

Off-TTY returns null: without \r rewriting, every tick would print
its own line into redirected output.
Chunk-wise read replaces buffering the whole asset with arrayBuffer(),
hashing incrementally so the binary is never held in memory. TTY output
rewrites one status line, and a failed download now closes it, cleans up
the staging file, and no longer strands a partial next to the binary.
The guide told users the binary downloads but not what they would see
while it did. Also fills the feature map's spec cell for self-update,
which had none.
The renderer's return type and downloadAndReplace's parameter declared
the same signature under two names. Spec prose loses its em dashes and
drops a line reference that went stale when the buffering path was cut.
@damusix
damusix merged commit 673a247 into main Sep 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant