Skip to main content

vcs_runner/
lib.rs

1//! VCS-specific helpers built on [`procpilot`]. Adds jj/git shorthand
2//! wrappers, repo detection, and output parsers.
3//!
4//! For generic subprocess execution (stdin, retry, timeout, custom envs),
5//! use [`procpilot::Cmd`] directly — it's re-exported here for convenience.
6
7mod detect;
8mod error;
9#[cfg(feature = "git-parse")]
10mod parse_git;
11#[cfg(feature = "jj-parse")]
12mod parse_jj;
13mod runner;
14mod types;
15
16pub use detect::{VcsBackend, detect_vcs};
17pub use error::RunError;
18#[cfg(feature = "git-parse")]
19pub use parse_git::parse_git_diff_name_status;
20#[cfg(feature = "jj-parse")]
21pub use parse_jj::{
22    BOOKMARK_TEMPLATE, LOG_TEMPLATE, BookmarkParseResult, LogParseResult, parse_bookmark_output,
23    parse_diff_summary, parse_log_output, parse_remote_list,
24};
25pub use runner::{
26    git_merge_base, is_transient_error, jj_current_operation_id, jj_divergent_change_ids,
27    jj_is_divergent_at_operation, jj_merge_base, jj_op_restore, jj_operation_log, run_git,
28    run_git_cancellable, run_git_utf8, run_git_utf8_cancellable, run_git_utf8_with_retry,
29    run_git_utf8_with_retry_cancellable, run_git_utf8_with_timeout, run_git_with_retry,
30    run_git_with_retry_cancellable, run_git_with_timeout, run_jj, run_jj_cancellable, run_jj_utf8,
31    run_jj_utf8_cancellable, run_jj_utf8_with_retry, run_jj_utf8_with_retry_cancellable,
32    run_jj_utf8_with_timeout, run_jj_with_retry, run_jj_with_retry_cancellable, run_jj_with_timeout,
33};
34
35// Re-export procpilot's generic subprocess API so vcs-runner consumers have
36// one dependency. Prefer these for anything non-VCS-specific.
37pub use procpilot::{
38    Cmd, CmdDisplay, DefaultRunner, Redirection, RetryPolicy, RunOutput, Runner,
39    STREAM_SUFFIX_SIZE, SpawnedProcess, StdinData, binary_available, binary_version,
40    default_transient,
41};
42
43pub use types::JjOperation;
44#[cfg(any(feature = "jj-parse", feature = "git-parse"))]
45pub use types::{FileChange, FileChangeKind};
46#[cfg(feature = "jj-parse")]
47pub use types::{Bookmark, ConflictState, ContentState, GitRemote, LogEntry, RemoteStatus, WorkingCopy};
48
49/// Common types and helpers for everyday VCS subprocess work.
50///
51/// `use vcs_runner::prelude::*;` brings in procpilot's standard set
52/// (`Cmd`, `RunError`, `RunOutput`, `Redirection`, `RetryPolicy`,
53/// `StdinData`, `SpawnedProcess`) plus the VCS-specific helpers
54/// (`run_jj`, `run_git`, retry/timeout variants, `jj_merge_base`,
55/// `git_merge_base`, `is_transient_error`, and the binary-availability
56/// checks).
57///
58/// Parser types and constants (`LogEntry`, `BOOKMARK_TEMPLATE`, …) stay
59/// out of the prelude — those callers know they need them and can
60/// import explicitly.
61pub mod prelude {
62    pub use procpilot::prelude::*;
63
64    pub use crate::{
65        VcsBackend, detect_vcs, git_available, git_merge_base, git_version, is_transient_error,
66        jj_available, jj_current_operation_id, jj_divergent_change_ids,
67        jj_is_divergent_at_operation, jj_merge_base, jj_op_restore, jj_operation_log, jj_version,
68        run_git, run_git_cancellable, run_git_utf8, run_git_utf8_cancellable,
69        run_git_utf8_with_retry, run_git_utf8_with_retry_cancellable, run_git_utf8_with_timeout,
70        run_git_with_retry, run_git_with_retry_cancellable, run_git_with_timeout, run_jj,
71        run_jj_cancellable, run_jj_utf8, run_jj_utf8_cancellable, run_jj_utf8_with_retry,
72        run_jj_utf8_with_retry_cancellable, run_jj_utf8_with_timeout, run_jj_with_retry,
73        run_jj_with_retry_cancellable, run_jj_with_timeout,
74    };
75}
76
77/// Check whether the `jj` binary is available on PATH.
78pub fn jj_available() -> bool {
79    binary_available("jj")
80}
81
82/// Get the jj version string, if available.
83pub fn jj_version() -> Option<String> {
84    binary_version("jj")
85}
86
87/// Check whether the `git` binary is available on PATH.
88pub fn git_available() -> bool {
89    binary_available("git")
90}
91
92/// Get the git version string, if available.
93pub fn git_version() -> Option<String> {
94    binary_version("git")
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn jj_available_returns_bool() {
103        let _ = jj_available();
104    }
105
106    #[test]
107    fn jj_version_matches_availability() {
108        if jj_available() {
109            let v = jj_version().expect("jj is installed");
110            assert!(v.contains("jj"));
111        } else {
112            assert!(jj_version().is_none());
113        }
114    }
115
116    #[test]
117    fn git_available_returns_bool() {
118        let _ = git_available();
119    }
120
121    #[test]
122    fn git_version_matches_availability() {
123        if git_available() {
124            let v = git_version().expect("git is installed");
125            assert!(v.contains("git"));
126        } else {
127            assert!(git_version().is_none());
128        }
129    }
130}