Skip to main content

git_proc/
rev_parse.rs

1use std::path::Path;
2
3/// Create a new `git rev-parse` command builder.
4#[must_use]
5pub fn new() -> RevParse<'static> {
6    RevParse::new()
7}
8
9/// Builder for `git rev-parse` command.
10///
11/// See `git rev-parse --help` for full documentation.
12#[derive(Debug)]
13pub struct RevParse<'a> {
14    repo_path: Option<&'a Path>,
15    abbrev_ref: bool,
16    symbolic_full_name: bool,
17    rev: Option<&'a str>,
18}
19
20crate::impl_repo_path!(RevParse);
21
22impl<'a> RevParse<'a> {
23    #[must_use]
24    fn new() -> Self {
25        Self {
26            repo_path: None,
27            abbrev_ref: false,
28            symbolic_full_name: false,
29            rev: None,
30        }
31    }
32
33    crate::flag_methods! {
34        /// Output short ref name (e.g., `main` instead of `refs/heads/main`).
35        ///
36        /// Corresponds to `--abbrev-ref`.
37        pub fn abbrev_ref / abbrev_ref_if, abbrev_ref, "Conditionally output short ref name."
38    }
39
40    crate::flag_methods! {
41        /// Output full symbolic ref name.
42        ///
43        /// Corresponds to `--symbolic-full-name`.
44        pub fn symbolic_full_name / symbolic_full_name_if, symbolic_full_name, "Conditionally output full symbolic ref name."
45    }
46
47    /// Set the revision to parse (e.g., `HEAD`, `@{u}`).
48    #[must_use]
49    pub fn rev(mut self, rev: &'a str) -> Self {
50        self.rev = Some(rev);
51        self
52    }
53}
54
55impl Default for RevParse<'_> {
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61impl crate::Build for RevParse<'_> {
62    fn build(self) -> cmd_proc::Command {
63        crate::base_command(self.repo_path)
64            .argument("rev-parse")
65            .optional_flag(self.abbrev_ref, "--abbrev-ref")
66            .optional_flag(self.symbolic_full_name, "--symbolic-full-name")
67            .optional_argument(self.rev)
68    }
69}
70
71#[cfg(feature = "test-utils")]
72impl RevParse<'_> {
73    /// Compare the built command with another command using debug representation.
74    ///
75    /// This is useful for testing command construction without executing.
76    pub fn test_eq(&self, other: &cmd_proc::Command) {
77        let command = crate::Build::build(Self {
78            repo_path: self.repo_path,
79            abbrev_ref: self.abbrev_ref,
80            symbolic_full_name: self.symbolic_full_name,
81            rev: self.rev,
82        });
83        command.test_eq(other);
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::Build;
91
92    #[tokio::test]
93    async fn test_rev_parse_head() {
94        let output = RevParse::new()
95            .rev("HEAD")
96            .build()
97            .capture_stdout()
98            .string()
99            .await
100            .unwrap();
101        assert!(!output.trim().is_empty());
102    }
103
104    #[tokio::test]
105    async fn test_rev_parse_abbrev_ref() {
106        let output = RevParse::new()
107            .abbrev_ref()
108            .rev("HEAD")
109            .build()
110            .capture_stdout()
111            .string()
112            .await
113            .unwrap();
114        assert!(!output.trim().is_empty());
115    }
116}