Skip to main content

run_with_progress_within

Function run_with_progress_within 

Source
pub async fn run_with_progress_within<R: ProcessRunner + ?Sized>(
    runner: &R,
    command: &Command,
    progress: &mut ProgressCallback<'_>,
    budget: OutputBudget,
) -> Result<()>
Expand description

run_with_progress with an explicit OutputBudget bounding the output it retains locally — the memory ceiling a long streamed run needs.

This is the streaming half of the contract budget_diagnostics applies to the captured twin of the same verbs. That one bounds the buffer processkit retains for a non-streamed clone/fetch; this one bounds the copy this function keeps in order to promote a rejected exit into a structured error. A streamed run needs both: the event stream delivers every line regardless of the command’s own OutputBufferPolicy, so without a ceiling here a git clone --progress of a large repository re-introduces exactly the unbounded retention the budget exists to prevent.

The ceiling is drop-oldest and never fail-loud, like OutputBudget::diagnostic_policy: passing it truncates what is retained, it never turns a successful (or plainly failed) run into ErrorReason::OutputTooLarge. Each stream carries the ceiling independentlystdout and stderr get their own budget, so the worst-case retained memory is about twice the cap, matching how OutputBudget rides a captured verb’s two streams. The retained tail is what a CLI’s fatal line sits in, so a bounded run stays classifiable by is_transient_fetch_error / is_lock_contention, and a non-zero exit is still promoted to a structured ErrorReason::Exit carrying that (truncated, non-empty) text.

Only what this function retains is bounded: progress is still invoked for every event, so a caller that wants more of the stream can keep it — bounded however it chooses — from its own callback.

§What the byte ceiling counts here

OutputBudget::bytes is charged against the retained text itself: the decoded content of the retained lines plus the single \n this function inserts between each retained pair. The invariant is therefore as direct as it looks — the stdout/stderr handed to the error is never longer than max_bytes bytes.

That is deliberately a third unit, and the two processkit ones are neither of them (see OutputBudget::bytes for those): the fail-loud content ceiling counts raw pipe bytes with every terminator charged, processkit’s own drop-oldest retention counts decoded line content with none charged, and this one charges exactly the separators it actually holds — one per retained pair. For n retained LF-terminated lines that is one byte less than the raw pipe bytes they arrived as, and n - 1 bytes more than processkit’s drop-mode accounting of the same lines. OutputBudget::with_max_lines caps the retained line count on top of that, dropping oldest-first too.

A single line longer than the byte cap is kept as its own tail (cut on a UTF-8 char boundary), not dropped whole as processkit’s drop-mode buffer would drop it: under the default \n line framing, carriage-return progress output — precisely what --progress emits — arrives as one ever-growing line, and dropping it whole would retain nothing at all of the stream this ceiling exists to bound.