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_merge_base, run_git, run_git_with_retry,
27    run_git_with_timeout, run_jj, run_jj_with_retry, run_jj_with_timeout,
28};
29
30// Re-export procpilot's generic subprocess API so vcs-runner consumers have
31// one dependency. Prefer these for anything non-VCS-specific.
32pub use procpilot::{
33    BeforeSpawnHook, Cmd, CmdDisplay, Redirection, RetryPolicy, RunOutput, STREAM_SUFFIX_SIZE,
34    StdinData, binary_available, binary_version, default_transient,
35};
36
37#[cfg(any(feature = "jj-parse", feature = "git-parse"))]
38pub use types::{FileChange, FileChangeKind};
39#[cfg(feature = "jj-parse")]
40pub use types::{Bookmark, ConflictState, ContentState, GitRemote, LogEntry, RemoteStatus, WorkingCopy};
41
42/// Check whether the `jj` binary is available on PATH.
43pub fn jj_available() -> bool {
44    binary_available("jj")
45}
46
47/// Get the jj version string, if available.
48pub fn jj_version() -> Option<String> {
49    binary_version("jj")
50}
51
52/// Check whether the `git` binary is available on PATH.
53pub fn git_available() -> bool {
54    binary_available("git")
55}
56
57/// Get the git version string, if available.
58pub fn git_version() -> Option<String> {
59    binary_version("git")
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn jj_available_returns_bool() {
68        let _ = jj_available();
69    }
70
71    #[test]
72    fn jj_version_matches_availability() {
73        if jj_available() {
74            let v = jj_version().expect("jj is installed");
75            assert!(v.contains("jj"));
76        } else {
77            assert!(jj_version().is_none());
78        }
79    }
80
81    #[test]
82    fn git_available_returns_bool() {
83        let _ = git_available();
84    }
85
86    #[test]
87    fn git_version_matches_availability() {
88        if git_available() {
89            let v = git_version().expect("git is installed");
90            assert!(v.contains("git"));
91        } else {
92            assert!(git_version().is_none());
93        }
94    }
95}