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
independently — stdout 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.