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 fetch;
77pub mod init;
78pub mod ls_remote;
79pub mod push;
80pub mod remote;
81pub mod rev_list;
82pub mod rev_parse;
83pub mod show;
84pub mod show_ref;
85pub mod status;
86pub mod url;
87pub mod worktree;
88
89use std::path::Path;
90
91pub use cmd_proc::CommandError;
92
93/// Trait for git command builders that support porcelain output.
94///
95/// Provides the `porcelain` and `porcelain_if` methods to set `--porcelain`.
96pub trait Porcelain: Sized {
97    /// Conditionally enable porcelain output (`--porcelain`).
98    fn porcelain_if(self, value: bool) -> Self;
99
100    /// Enable porcelain output (`--porcelain`).
101    fn porcelain(self) -> Self {
102        self.porcelain_if(true)
103    }
104}
105
106/// Generate inherent `porcelain` / `porcelain_if` methods and a `Porcelain` trait implementation.
107///
108/// The inherent methods set the `porcelain` field.
109/// The trait implementation delegates to the inherent methods.
110///
111/// This ensures callers can use `.porcelain()` without importing the `Porcelain` trait,
112/// while the trait remains available for generic bounds.
113#[doc(hidden)]
114#[macro_export]
115macro_rules! impl_porcelain {
116    ($ty:ident) => {
117        impl<'a> $ty<'a> {
118            /// Give output in machine-parseable format.
119            ///
120            /// Corresponds to `--porcelain`.
121            #[must_use]
122            pub fn porcelain(self) -> Self {
123                self.porcelain_if(true)
124            }
125
126            /// Conditionally enable porcelain output.
127            #[must_use]
128            pub fn porcelain_if(mut self, value: bool) -> Self {
129                self.porcelain = value;
130                self
131            }
132        }
133
134        impl<'a> $crate::Porcelain for $ty<'a> {
135            fn porcelain_if(self, value: bool) -> Self {
136                self.porcelain_if(value)
137            }
138        }
139    };
140}
141
142/// Trait for git command builders that support a repository path.
143///
144/// Provides the `repo_path` method to set `-C <path>`.
145#[must_use = "repo_path returns a modified builder; the return value must be used"]
146pub trait RepoPath<'a>: Sized {
147    /// Set the repository path (`-C <path>`).
148    fn repo_path(self, path: &'a Path) -> Self;
149}
150
151/// Trait for building a command without executing it.
152///
153/// All git command builders implement this trait, allowing you to
154/// access the underlying `cmd_proc::Command` for custom execution.
155///
156/// # Example
157///
158/// ```ignore
159/// use git_proc::Build;
160/// use cmd_proc::Stdio;
161///
162/// git_proc::fetch::new()
163///     .all()
164///     .build()
165///     .spawn()
166///     .stderr(Stdio::Null)
167///     .run()?;
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}