Skip to main content

git_proc/
lib.rs

1#![doc = include_str!("../README.md")]
2
3/// Generate a pair of flag methods: unconditional and conditional.
4///
5/// The unconditional method calls the conditional one with `true`.
6///
7/// # Example
8///
9/// ```ignore
10/// flag_methods! {
11///     /// Enable foo mode.
12///     ///
13///     /// Corresponds to `--foo`.
14///     pub fn foo / foo_if, foo_field, "Conditionally enable foo mode."
15/// }
16/// ```
17///
18/// Generates:
19/// - `pub fn foo(self) -> Self` - calls `foo_if(true)`
20/// - `pub fn foo_if(mut self, value: bool) -> Self` - sets `self.foo_field = value`
21#[doc(hidden)]
22#[macro_export]
23macro_rules! flag_methods {
24    (
25        $(#[$attr:meta])*
26        $vis:vis fn $name:ident / $name_if:ident, $field:ident, $doc_if:literal
27    ) => {
28        $(#[$attr])*
29        #[must_use]
30        $vis fn $name(self) -> Self {
31            self.$name_if(true)
32        }
33
34        #[doc = $doc_if]
35        #[must_use]
36        $vis fn $name_if(mut self, value: bool) -> Self {
37            self.$field = value;
38            self
39        }
40    };
41}
42
43/// Generate an inherent `repo_path` method and a `RepoPath` trait implementation.
44///
45/// The inherent method sets the `repo_path` field to `Some(path)`.
46/// The trait implementation delegates to the inherent method.
47///
48/// This ensures callers can use `.repo_path()` without importing the `RepoPath` trait,
49/// while the trait remains available for generic bounds.
50#[doc(hidden)]
51#[macro_export]
52macro_rules! impl_repo_path {
53    ($ty:ident) => {
54        impl<'a> $ty<'a> {
55            /// Set the repository path (`-C <path>`).
56            #[must_use]
57            pub fn repo_path(mut self, path: &'a std::path::Path) -> Self {
58                self.repo_path = Some(path);
59                self
60            }
61        }
62
63        impl<'a> $crate::RepoPath<'a> for $ty<'a> {
64            fn repo_path(self, path: &'a std::path::Path) -> Self {
65                self.repo_path(path)
66            }
67        }
68    };
69}
70
71pub mod add;
72pub mod branch;
73pub mod clone;
74pub mod commit;
75pub mod config;
76pub mod diff;
77pub mod fetch;
78pub mod init;
79pub mod ls_remote;
80pub mod push;
81pub mod remote;
82pub mod repository;
83pub mod rev_list;
84pub mod rev_parse;
85pub mod show;
86pub mod show_ref;
87pub mod status;
88pub mod worktree;
89
90use std::path::Path;
91
92pub use cmd_proc::CommandError;
93
94/// Trait for git command builders that support porcelain output.
95///
96/// Provides the `porcelain` and `porcelain_if` methods to set `--porcelain`.
97pub trait Porcelain: Sized {
98    /// Conditionally enable porcelain output (`--porcelain`).
99    fn porcelain_if(self, value: bool) -> Self;
100
101    /// Enable porcelain output (`--porcelain`).
102    fn porcelain(self) -> Self {
103        self.porcelain_if(true)
104    }
105}
106
107/// Generate inherent `porcelain` / `porcelain_if` methods and a `Porcelain` trait implementation.
108///
109/// The inherent methods set the `porcelain` field.
110/// The trait implementation delegates to the inherent methods.
111///
112/// This ensures callers can use `.porcelain()` without importing the `Porcelain` trait,
113/// while the trait remains available for generic bounds.
114#[doc(hidden)]
115#[macro_export]
116macro_rules! impl_porcelain {
117    ($ty:ident) => {
118        impl<'a> $ty<'a> {
119            /// Give output in machine-parseable format.
120            ///
121            /// Corresponds to `--porcelain`.
122            #[must_use]
123            pub fn porcelain(self) -> Self {
124                self.porcelain_if(true)
125            }
126
127            /// Conditionally enable porcelain output.
128            #[must_use]
129            pub fn porcelain_if(mut self, value: bool) -> Self {
130                self.porcelain = value;
131                self
132            }
133        }
134
135        impl<'a> $crate::Porcelain for $ty<'a> {
136            fn porcelain_if(self, value: bool) -> Self {
137                self.porcelain_if(value)
138            }
139        }
140    };
141}
142
143/// Trait for git command builders that support a repository path.
144///
145/// Provides the `repo_path` method to set `-C <path>`.
146#[must_use = "repo_path returns a modified builder; the return value must be used"]
147pub trait RepoPath<'a>: Sized {
148    /// Set the repository path (`-C <path>`).
149    fn repo_path(self, path: &'a Path) -> Self;
150}
151
152/// Trait for building a command without executing it.
153///
154/// All git command builders implement this trait, allowing you to
155/// access the underlying `cmd_proc::Command` for custom execution.
156///
157/// # Example
158///
159/// ```ignore
160/// use git_proc::Build;
161///
162/// git_proc::fetch::new()
163///     .all()
164///     .build()
165///     .stderr_null()
166///     .status()
167///     .await?;
168/// ```
169pub trait Build {
170    /// Build the command without executing it.
171    fn build(self) -> cmd_proc::Command;
172}
173
174/// Create a command builder with optional repository path.
175///
176/// If `repo_path` is `Some`, adds `-C <path>` to the command.
177/// If `repo_path` is `None`, uses current working directory.
178fn base_command(repo_path: Option<&Path>) -> cmd_proc::Command {
179    cmd_proc::Command::new("git").optional_option("-C", repo_path)
180}