mix ymer_node.build.live_output (Ymer Node v0.2.1)

Copy Markdown View Source

A subprocess's output reaching the terminal as it is produced — faithful for valid UTF-8, with anything unreadable shown as , and unable to stop the task that runs it, whatever bytes it carries.

The port hands System.cmd/3's collectable flat 65536-byte chunks, so a boundary falls wherever the byte count lands — regularly inside one of the box-drawing characters a compiler diagnostic is framed with. The device those bytes go to is a unicode one, and stays one when stdout is redirected to a file, so half a codepoint reaching it raises instead of printing. IO.stream/2's second argument is no lever against that: :line and a byte count alike shape the read direction only, and the collectable it returns writes every chunk it is handed straight to the device whichever one is passed — so the line-at-a-time framing that argument suggests was never real, and tuning it was never a fix.

This collectable therefore never presents an incomplete or invalid sequence to the device. It holds back a trailing sequence the bytes so far still allow to be a codepoint — at most three bytes — and prepends it to the next chunk; a sequence a byte has already ruled out has its first byte written as and the remainder re-split behind it. Nothing else is read out of the bytes: no lines, no escape sequences, no assumption about what the subprocess prints. That is what keeps a carriage-return progress redraw on screen as it arrives, where a collectable buffering by line shows docker's fast layers once, at the end.

What it collects must be iodata: System.cmd/3 opens its port with :binary, so that is what it is handed. Chardata is not accepted, and the narrowing is silent rather than loud — a codepoint list is read as bytes, so codepoints 128–255 come out as and anything larger raises in IO.iodata_to_binary/1.

The device is a field rather than a fixed :stdio because a StringIO enforces the same encoding: a test can prove the property against one without capturing the run's own output.