Skip to main content

ManagedClient

Struct ManagedClient 

Source
pub struct ManagedClient<R: ProcessRunner = JobRunner> { /* private fields */ }
Expand description

A CliClient wrapper that adds two opt-in concerns the CLI wrappers (vcs-git, vcs-jj, vcs-github, vcs-gitlab) all share, without touching a single call site:

  1. Lock-contention retry (is_lock_contention) per a RetryPolicy — off by default (RetryPolicy::none); enable with with_retry. Safe even for mutating commands, since lock contention is a clean pre-execution failure.
  2. Credential injection from an opt-in CredentialProvider — off by default (no provider); attach one with with_credentials. When a forge token-env binding is configured (with_token_env), every command run through this client gets the resolved token in that environment variable (e.g. GH_TOKEN). Backends that inject the secret differently (git’s credential.helper) instead call resolve_credential at the command site. Resolution happens once per call, before the retry loop.

Both default to inert, so a client with neither configured behaves exactly like a bare CliClient.

Implementations§

Source§

impl ManagedClient<JobRunner>

Source

pub fn new(program: impl AsRef<OsStr>) -> Self

A retrying client driving program on the real job-backed runner (no retry until with_retry).

Source§

impl<R: ProcessRunner> ManagedClient<R>

Source

pub fn with_runner(program: impl AsRef<OsStr>, runner: R) -> Self

A retrying client driving program on runner — inject a fake in tests.

Source

pub fn with_retry(self, policy: RetryPolicy) -> Self

Set the lock-contention retry policy (opt-in; default is no retry).

Source

pub fn retry_policy(&self) -> RetryPolicy

The active retry policy.

Source

pub fn with_credentials(self, provider: Arc<dyn CredentialProvider>) -> Self

Attach a CredentialProvider (opt-in; default is none → ambient auth). The provider is consulted per operation: automatically when a with_token_env binding is set, or on demand via resolve_credential.

Precedence: a resolved token is injected after any default_env, so the provider wins over a static default and over the ambient CLI login. Cancellation: a default_cancel_on token bounds the spawned process, not provider resolution — if your provider does slow I/O (a vault lookup), bound it yourself.

Source

pub fn with_token_env( self, service: CredentialService, var: &'static str, ) -> Self

Bind the resolved token to an environment variable injected on every command this client runs (the forge case: GH_TOKEN, GITLAB_TOKEN). The service tags the CredentialRequest. No effect without a provider.

Source

pub fn has_credentials(&self) -> bool

Whether a credential provider is configured.

Source

pub async fn resolve_credential( &self, service: CredentialService, host: Option<&str>, ) -> Result<Option<Credential>>

Resolve a credential for service/host from the configured provider, or Ok(None) if no provider is set or it defers to ambient auth. Backends that inject the secret at the command site (git’s credential.helper) call this directly; the forge token-env path uses it internally.

Source

pub fn default_timeout(self, timeout: Duration) -> Self

Apply a default timeout to every command this client builds.

Source

pub fn default_env( self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>, ) -> Self

Set an environment variable on every command this client builds.

Source

pub fn default_env_remove(self, key: impl AsRef<OsStr>) -> Self

Remove an inherited environment variable on every command this client builds.

Source

pub fn default_cancel_on(self, token: CancellationToken) -> Self

Cancel every command this client builds when token fires.

Source

pub fn command<I, S>(&self, args: I) -> Command
where I: IntoIterator<Item = S>, S: AsRef<OsStr>,

Build a Command for this client’s program (passthrough).

Source

pub fn command_in<I, S>(&self, dir: &Path, args: I) -> Command
where I: IntoIterator<Item = S>, S: AsRef<OsStr>,

Build a Command bound to dir (passthrough).

Source

pub fn runner(&self) -> &R

The underlying process runner (passthrough — e.g. for output_all).

Source

pub async fn run(&self, call: impl IntoCommand<R>) -> Result<String>

Like CliClient::run, with credential injection and lock-retry.

Source

pub async fn run_unit(&self, call: impl IntoCommand<R>) -> Result<()>

Like CliClient::run_unit, with credential injection and lock-retry.

Source

pub async fn output_string( &self, call: impl IntoCommand<R>, ) -> Result<ProcessResult<String>>

Like CliClient::output_string, with credential injection. No lock-retry: output_string returns Ok on a non-zero exit (it captures the result), so a lock failure surfaces as an Ok here, not an Err the retry predicate could match — route mutations that need lock-retry through run/run_unit instead.

Source

pub async fn run_untrimmed(&self, call: impl IntoCommand<R>) -> Result<String>

Like run, but returns stdout verbatim — no trim_end. For content-returning verbs (a file’s bytes at a rev, a diff, a raw template render) where the trailing newline(s) are part of the value, not noise: trimming them corrupts a read-modify-write round-trip and desyncs a diff’s last hunk from its @@ line count. Exit-checked like run; no lock-retry (a content read is not a mutation).

Source

pub async fn probe(&self, call: impl IntoCommand<R>) -> Result<bool>

Like CliClient::probe (zero-or-nonzero exit → bool), with credential injection and lock-retry.

Source

pub async fn exit_code(&self, call: impl IntoCommand<R>) -> Result<i32>

Like CliClient::exit_code (the raw exit code; a spawn failure or timeout still errors), with credential injection and lock-retry.

Source

pub async fn parse<T>( &self, call: impl IntoCommand<R>, parser: impl FnOnce(&str) -> T + Send, ) -> Result<T>
where T: Send,

Like CliClient::parse (credential injection applied; the FnOnce parser can’t be re-run, so lock-retry does not — parsing is a read, where lock contention is not a concern anyway).

Source

pub async fn try_parse<T>( &self, call: impl IntoCommand<R>, parser: impl FnOnce(&str) -> Result<T> + Send, ) -> Result<T>
where T: Send,

Like CliClient::try_parse (credential injection applied; FnOnce parser, and a read, so no lock-retry).

Trait Implementations§

Source§

impl<R: ProcessRunner> Debug for ManagedClient<R>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<R = JobRunner> !RefUnwindSafe for ManagedClient<R>

§

impl<R = JobRunner> !UnwindSafe for ManagedClient<R>

§

impl<R> Freeze for ManagedClient<R>
where R: Freeze,

§

impl<R> Send for ManagedClient<R>

§

impl<R> Sync for ManagedClient<R>

§

impl<R> Unpin for ManagedClient<R>
where R: Unpin,

§

impl<R> UnsafeUnpin for ManagedClient<R>
where R: UnsafeUnpin,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.