Skip to main content

Crate vcs_jj

Crate vcs_jj 

Source
Expand description

vcs-jj — automate Jujutsu (jj) from Rust by driving the jj CLI.

It shells out to the installed jj binary and parses its templated output into typed values — so you get jj’s own behaviour and config, not a reimplementation of the operation log or backend. Async throughout, structured errors, and mockable. Every command runs inside an OS job (via processkit) so a jj subprocess tree can never be orphaned, and honours an optional per-client timeout.

§The surface

There is deliberately no Jj::hardened() counterpart to vcs-git’s untrusted-repo profile: jj has no repo-local hooks, and its config comes from the user/repo TOML files jj itself trusts. In a colocated repo the risk lives on the git side — git hooks fire when git commands run there, so harden the Git client you point at it.

§Recipes

Read state — depend on the trait so the same code takes a real client or a mock:

use std::path::Path;
use vcs_jj::{Jj, JjApi};
let jj = Jj::new();
let dir = Path::new(".");
let current = jj.current_change(dir).await?;       // the working-copy change `@`
let dirty = !jj.status(dir).await?.is_empty();     // any working-copy edit?

Mutate inside a transaction — an Err rolls the op log back:

use std::path::Path;
use vcs_jj::Jj;
let dir = Path::new(".");
jj.transaction(dir, |tx| async move {
    tx.describe("wip").await?;
    tx.new_change("next").await        // an Err here undoes the describe
})
.await?;

§Testing

Two seams: enable the mock feature for a mockall-generated MockJjApi (stub whole methods), or inject a ScriptedRunner with Jj::with_runner to exercise the real argv-building and parsing against canned output. The cross-cutting testing patterns live in vcs-testkit’s guide.

§Safety

Every caller value placed in a bare positional argv slot (bookmark name, revset, operation id, merge parent, …) is refused before spawning if it is empty or starts with - (jj would parse it as a flag); flag-value slots (-r <revset>, -m <msg>) and the run/run_raw escape hatches are not guarded. For eager validation at an input boundary, RevsetExpr validates up front. Paths go through the exact-path JjFileset form.

§In-depth guide

Beyond this page, this crate ships a full how-to guide — rendered on docs.rs from docs/. See the guide module. The conflict model is covered by vcs-git’s conflicts guide, which spans both backends.

Modules§

__mock_MockJjApi
__mock_MockJjApi_JjApi
blocking
Synchronous, best-effort helpers for contexts that cannot .await — chiefly a Drop guard. They shell out through std::process directly (no async, no job-containment), so reserve them for short-lived cleanup.
conflict
Typed model of jj’s materialized conflict markers — parse a conflicted file’s content into structured regions and write a chosen resolution back. Pure functions (no subprocess), so everything here is hermetic.
guide
vcs-jj — Jujutsu CLI guide

Structs§

AnnotationLine
One line of jj file annotate output: which change last touched it.
Bookmark
A jj bookmark, parsed from jj bookmark list output.
BookmarkRef
A bookmark from jj bookmark list -a — local or remote-tracking.
CancellationTokencancellation
A token which can be used to signal a cancellation request to one or more tasks.
Change
A jj change, parsed from a \t-delimited template row.
ChangedPath
One entry from jj diff --summary: a single-letter status (M/A/D/…) and the (forward-slash-normalised) path it applies to — the new path for a rename/copy, with the original on old_path.
DiffStat
Aggregate line/file counts from a diff stat (git diff --shortstat, jj diff --stat).
FileDiff
One file’s entry in a parsed git-format unified diff (git diff or jj diff --git).
Hunk
A single @@ … @@ hunk within a FileDiff.
Jj
The real jj client. Generic over the ProcessRunner so tests can inject a fake process executor; Jj::new() uses the real job-backed runner.
JjAt
A Jj client with a working directory bound, so calls drop the leading dir argument — jj.at(dir).status() is jj.status(dir). Construct one with Jj::at (or, through the facade, vcs_core::Repo::jj_at). Cheap to copy: it only borrows the client and the path.
JjCapabilities
What the installed jj binary supports, probed via JjApi::capabilities. A value type — the client holds no state, so probe once and keep the result (callers cache it).
JjFileset
An exact-path jj fileset (file:"<path>"), so path metacharacters like (, ), |, * are treated literally rather than as fileset operators.
JjVersion
A parsed CLI version (major.minor.patch). Ord compares numerically, so a caller can gate a feature on a minimum version; Hash lets it key a map (e.g. a per-version capability cache).
MockJjApi
The jj operations this crate exposes — the interface consumers code against and mock in tests.
Operation
One entry of jj op log (an operation-log row).
ProcessResult
The captured result of running a process to completion.
RevsetExpr
A pre-validated revset expression, for callers that accept revsets from untrusted input (UIs, bots, agents) and want to fail early. Deliberately minimal — jj’s revset grammar is too rich to validate here — it only guarantees the expression is non-empty and cannot be parsed as a flag (no leading -), matching the internal guard the positional-revset methods apply anyway. The dir-taking methods stay &str; this type is optional up-front validation, not a required wrapper.
SquashPaths
Options for JjApi::squash_paths (jj squash --from <from> --into <into> [--use-destination-message] <filesets>).
Workspace
A workspace from jj workspace list (rendered with WORKSPACE_TEMPLATE).
WorkspaceAdd
Options for JjApi::workspace_add (jj workspace add).

Enums§

ChangeKind
How a file changed in a unified diff.
DiffLine
One line inside a Hunk, tagged by its role. The stored text excludes the leading /+/- marker and the line terminator — a CRLF-origin diff’s trailing \r is stripped along with the \n, so reconstruct exact bytes from FileDiff::raw, not from these lines.
DiffSpec
What a JjApi::diff / JjApi::diff_text call compares.
Error
Errors produced when launching or running a child process.
SparseMode
How a new workspace inherits sparse patterns (jj workspace add --sparse-patterns <mode>).

Constants§

BINARY
Name of the underlying CLI binary this crate drives.

Traits§

JjApi
The jj operations this crate exposes — the interface consumers code against and mock in tests.

Functions§

is_transient_fetch_error
Whether a failed fetch/fetch_remote_branch/remote_branch_exists looks transient (DNS, timeout, dropped connection) and is worth retrying.
parse_diff
Parse a git-format unified diff into one FileDiff per file. Works on git diff and jj diff --git output alike. Public so a consumer can parse diff text it obtained by other means.

Type Aliases§

Result
Crate result alias.