Skip to main content

Crate vcs_cli_support

Crate vcs_cli_support 

Source
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 surfaced Error::Spawn names the right program.
  • FETCH_ATTEMPTS / FETCH_BACKOFF — the shared transient-retry policy for fetch (one try plus two retries, fixed backoff between them).
  • is_merge_conflict / is_nothing_to_commit / is_transient_fetch_error — classify a returned Error so callers branch on intent (“conflict, resolve it”; “nothing to commit, no-op”; “transient, retry”) instead of matching on error internals. They inspect captured Error::Exit output against fixed marker lists (and treat a processkit Error::Timeout as 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_commit stopped on a merge conflict. (jj surfaces conflicts as state rather than as errors, so this only fires on git output — see vcs_core::Error::is_merge_conflict.)
is_nothing_to_commit
Whether a failed commit/commit_paths reported 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_exists looks 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 an Error::Spawn naming program. Flag-VALUE positions (-m <msg>, --branch <b>) don’t need this — the CLI consumes the next token verbatim there.