Expand description
vcs-cli-support — the processkit-coupled plumbing the CLI wrappers reuse.
vcs-git / vcs-jj / vcs-github all drive a CLI through processkit, so
they share three concerns that touch processkit::Error: an argv injection
guard, a fetch-retry policy, and a set of Error classifiers. Extracting them
here keeps the std-only vcs-diff clean of the processkit dependency, and —
more to the point — keeps the marker lists and classifier logic from drifting
between backends. The wrapper crates re-export these items (so you reach them
as vcs_git::is_merge_conflict, not via this crate’s name) and rarely name
vcs-cli-support directly.
§The surface
reject_flag_like— the injection guard for bare positional argv slots. A caller value that is empty/whitespace, or starts with-, is refused before spawning (the CLI would parse it as a flag); flag-value slots (-m <msg>) are consumed verbatim and skip the check. Wrappers call it with their own binary name so the surfacedError::Spawnnames the rightprogram.FETCH_ATTEMPTS/FETCH_BACKOFF— the shared transient-retry policy forfetch(one try plus two retries, fixed backoff between them).is_merge_conflict/is_nothing_to_commit/is_transient_fetch_error— classify a returnedErrorso callers branch on intent (“conflict, resolve it”; “nothing to commit, no-op”; “transient, retry”) instead of matching on error internals. They inspect capturedError::Exitoutput against fixed marker lists (and treat aprocesskitError::Timeoutas transient); any unfamiliar#[non_exhaustive]variant falls through to “no”.
§Recipes
Classify a failed fetch to drive a retry decision — branch on intent, not on
the error’s internals:
use vcs_cli_support::{is_transient_fetch_error, FETCH_ATTEMPTS, FETCH_BACKOFF};
for attempt in 1..=FETCH_ATTEMPTS {
match run() {
Ok(()) => break,
Err(e) if is_transient_fetch_error(&e) && attempt < FETCH_ATTEMPTS => {
std::thread::sleep(FETCH_BACKOFF); // DNS/timeout — worth a retry
}
Err(e) => return Err(e), // anything else: give up
}
}Constants§
- FETCH_
ATTEMPTS - Total attempts for a transient-retried
fetch(1 try + 2 retries). - FETCH_
BACKOFF - Fixed backoff between fetch retries.
Functions§
- is_
merge_ conflict - Whether a failed
merge/merge_commitstopped on a merge conflict. (jj surfaces conflicts as state rather than as errors, so this only fires on git output — seevcs_core::Error::is_merge_conflict.) - is_
nothing_ to_ commit - Whether a failed
commit/commit_pathsreported nothing to commit (a clean tree), as opposed to a real error. - is_
transient_ fetch_ error - Whether a failed
fetch/fetch_remote_branch/remote_branch_existslooks transient (DNS, timeout, dropped connection) and is worth retrying. - reject_
flag_ like - Injection guard for bare positional argv slots: a caller-supplied value with a
leading
-would be parsed by the CLI as a flag (verified:git checkout -evil→ “unknown switch”; jj likewise), and an empty (or whitespace-only) value silently changes most commands’ meaning. Refuse both before anything spawns, surfacing anError::Spawnnamingprogram. Flag-VALUE positions (-m <msg>,--branch <b>) don’t need this — the CLI consumes the next token verbatim there.